2 * op5 NOTE: I found this online and stuck it in here. It doesn't
3 * necessarily work for us, but at least now we have the expanded
6 * Easy Widgets 2.0 for jQuery and jQuery UI
8 * David Esperalta <http://www.davidesperalta.com/>
10 * More information, examples and latest version in the website:
11 * <http://www.bitacora.davidesperalta.com/archives/projects/easywidgets/>
13 * I based my work on a tutorial writen by James Padolsey
14 * <http://nettuts.com/tutorials/javascript-ajax/inettuts/>
16 * You should have received a copy of the GNU General Public License
17 * along with Easy Widgets. If not, see <http://www.gnu.org/licenses/>
22 ///////////////////////////
23 // Public plugin methods //
24 ///////////////////////////
27 * Main public method of plugin
29 * Call this method to initialize the plugin, that prepare all the available
30 * widgets in the document, and execute the appropiate task on every widget.
32 * Basically call the InitializeWidgets() private function, with the second
33 * param by default: using this method we not prepare widgets on demand, but
34 * prepare all widgets found in the document.
36 * See the mentioned function for more details, and how we use this function
37 * too in another plugin public method: AddEasyWidget(), see it for details.
40 * @see InitializeWidgets()
41 * @param settings Array with the plugin settings
42 * @return Boolean True in every case
45 $.fn
.EasyWidgets = function(settings
) {
46 InitializeWidgets(settings
, false);
51 * Add a new widget "on demand"
53 * This public method can be use to add a new widget "on demand" into certain
54 * place. The method need the HTML markup for widget, and this can specify
55 * all the available widget options.
57 * In this method we use the private InitializeWidgets() function, also used
58 * in another public method of the plugin: EasyWidgets(). Note that in this
59 * case the second param for this funtion specify that in this case we want
60 * to add a widget "on demand".
62 * For more details see the refered private function.
65 * @see InitializeWidgets()
66 * @param html String Widget HTML markup
67 * @param placeId String Element ID to place the Widget
68 * @param settings Array with the plugin settings
69 * @return Boolean True if widget is finally added, False if not
72 $.fn
.AddEasyWidget = function(html
, placeId
, settings
) {
75 var s
= $.extend(true, $.fn
.EasyWidgets
.defaults
, settings
);
76 if ($.isFunction(s
.callbacks
.onAddQuery
)) {
77 canAdd
= s
.callbacks
.onAddQuery(widget
, placeId
);
80 $('#' + placeId
).append(html
);
81 if ($.isFunction(s
.callbacks
.onAdd
)) {
82 s
.callbacks
.onAdd(widget
, placeId
);
84 InitializeWidgets(s
, true);
92 * Disable all widgets (fix then) in document
94 * This public method can be use to fix the widgets on document, in other
95 * words, disable the widgets, because the user cant move this after the
96 * widgets as been disables.
99 * @see EnableEasyWidgets()
100 * @param settings Array with the plugin settings
101 * @return Boolean True if widgets are finally disables, False if not
104 $.fn
.DisableEasyWidgets = function(settings
) {
105 var canDisable
= true;
106 var s
= $.extend(true, $.fn
.EasyWidgets
.defaults
, settings
);
107 if ($.isFunction(s
.callbacks
.onDisableQuery
)) {
108 canDisable
= s
.callbacks
.onDisableQuery();
111 $(s
.selectors
.places
).sortable('disable');
112 $(s
.selectors
.widget
).each(function() {
113 var widget
= $(this);
114 if (widget
.hasClass(s
.options
.movable
)) {
115 widget
.find(s
.selectors
.header
).css('cursor', 'default');
116 widget
.find(s
.selectors
.widgetMenu
).css('display', 'none');
119 if ($.isFunction(s
.callbacks
.onDisable
)) {
120 s
.callbacks
.onDisable();
122 SetCookie(s
.cookies
.disableName
, 1, s
);
130 * Enable all widgets (make movables) in document
132 * This public method can be use to make movables the widgets on document,
133 * in other words, enable the widgets, because the user can move this after
134 * the widgets as been enables.
136 * Note that the widgets are enables by default, so, this method have sense
137 * in case that you use before another method of plugin: DisableEasyWidgets()
140 * @see DisableEasyWidgets()
141 * @param settings Array with the plugin settings
142 * @return Boolean True if widgets are finally enables, False if not
145 $.fn
.EnableEasyWidgets = function(settings
) {
146 var canEnable
= true;
147 var s
= $.extend(true, $.fn
.EasyWidgets
.defaults
, settings
);
148 if ($.isFunction(s
.callbacks
.onEnableQuery
)) {
149 canEnable
= s
.callbacks
.onEnableQuery();
152 $(s
.selectors
.places
).sortable('enable');
153 $(s
.selectors
.widget
).each(function() {
154 var widget
= $(this);
155 if (widget
.hasClass(s
.options
.movable
)) {
156 widget
.find(s
.selectors
.header
).css('cursor', 'move');
159 if ($.isFunction(s
.callbacks
.onEnable
)) {
160 s
.callbacks
.onEnable();
162 if (s
.behaviour
.useCookies
) {
163 SetCookie(s
.cookies
.disableName
, 0, s
);
172 * Hide all widgets in document
174 * This public method can be use to hide all the document visible widgets.
175 * Note that this method and related is thinking if you use the plugin
178 * In other case, you can use directly something like this:
180 * $('widgets-class-selector').hide();
182 * So, this method can sense if you use the plugin cookies feature, because
183 * the plugin update the appropiate cookie with the needed information, to
184 * mantain the widgets hidden even if user refresh the page.
187 * @see HideEasyWidget()
188 * @see ShowEasyWidgets()
189 * @param settings Array with the plugin settings
190 * @return Boolean True in every case
193 $.fn
.HideEasyWidgets = function(settings
) {
194 var s
= $.extend(true, $.fn
.EasyWidgets
.defaults
, settings
);
195 $(s
.selectors
.widget
+ ':visible').each(function() {
197 var thisWidget
= $(this);
198 var thisWidgetId
= thisWidget
.attr('id');
199 if ($.isFunction(s
.callbacks
.onHideQuery
)) {
200 canHide
= s
.callbacks
.onHideQuery(thisWidget
);
205 s
.effects
.widgetHide
,
206 s
.effects
.effectDuration
,
209 if (s
.behaviour
.useCookies
&& thisWidgetId
) {
210 UpdateCookie(thisWidgetId
, s
.cookies
.closeName
, s
);
212 if ($.isFunction(s
.callbacks
.onHide
)) {
213 s
.callbacks
.onHide(thisWidget
);
221 * Show all widgets in document
223 * This public method can be use to show all the document hidden widgets.
224 * Note that this method and related is thinking if you use the plugin
227 * In other case, you can use directly something like this:
229 * $('widgets-class-selector').show();
231 * So, this method can sense if you use the plugin cookies feature, because
232 * the plugin update the appropiate cookie with the needed information, to
233 * mantain the widgets showing even if user refresh the page.
236 * @see ShowEasyWidget()
237 * @see HideEasyWidgets()
238 * @param settings Array with the plugin settings
239 * @return Boolean True in every case
242 $.fn
.ShowEasyWidgets = function(settings
) {
243 var s
= $.extend(true, $.fn
.EasyWidgets
.defaults
, settings
);
244 $(s
.selectors
.widget
+ ':hidden').each(function() {
246 var widget
= $(this);
247 var widgetId
= widget
.attr('id');
248 var haveId
= ($.trim(widgetId
) != '');
249 if ($.isFunction(s
.callbacks
.onShowQuery
)) {
250 canShow
= s
.callbacks
.onShowQuery(widget
);
255 s
.effects
.widgetShow
,
256 s
.effects
.effectDuration
,
259 if (haveId
&& s
.behaviour
.useCookies
) {
260 CleanCookie(widgetId
, s
.cookies
.closeName
, s
);
262 if ($.isFunction(s
.callbacks
.onShow
)) {
263 s
.callbacks
.onShow(widget
);
271 * Show an individual widget
273 * This public method can be use to show an individual hidden widget.
274 * Note that this method and related is thinking if you use the plugin
277 * In other case, you can use directly something like this:
279 * $('widget-id-selector').show();
281 * So, this method can sense if you use the plugin cookies feature, because
282 * the plugin update the appropiate cookie with the needed information, to
283 * mantain the widgets showing even if user refresh the page.
286 * @see HideEasyWidget()
287 * @see ShowEasyWidgets()
288 * @param widgetId String Widget element identifier
289 * @param settings Array with the plugin settings
290 * @return Boolean True if widget finally is show, False if not
293 $.fn
.ShowEasyWidget = function(widgetId
, settings
) {
295 var widget
= $('#' + widgetId
);
296 if (widget
.css('display') == 'none') {
297 var s
= $.extend(true, $.fn
.EasyWidgets
.defaults
, settings
);
298 if ($.isFunction(s
.callbacks
.onShowQuery
)) {
299 canShow
= s
.callbacks
.onShowQuery(widget
);
304 s
.effects
.widgetShow
,
305 s
.effects
.effectDuration
,
308 if (s
.behaviour
.useCookies
) {
309 CleanCookie(widgetId
, s
.cookies
.closeName
, s
);
311 if ($.isFunction(s
.callbacks
.onShow
)) {
312 s
.callbacks
.onShow(widget
);
324 * Hide an individual widget
326 * This public method can be use to hide an individual visible widget.
327 * Note that this method and related is thinking if you use the plugin
330 * In other case, you can use directly something like this:
332 * $('widget-id-selector').hide();
334 * So, this method can sense if you use the plugin cookies feature, because
335 * the plugin update the appropiate cookie with the needed information, to
336 * mantain the widgets showing even if user refresh the page.
339 * @see ShowEasyWidget()
340 * @see HideEasyWidgets()
341 * @param widgetId String Widget element identifier
342 * @param settings Array with the plugin settings
343 * @return Boolean True if widget finally is hide, False if not
346 $.fn
.HideEasyWidget = function(widgetId
, settings
) {
348 var widget
= $('#' + widgetId
);
349 if (widget
.css('display') != 'none') {
350 var s
= $.extend(true, $.fn
.EasyWidgets
.defaults
, settings
);
351 if ($.isFunction(s
.callbacks
.onHideQuery
)) {
352 canHide
= s
.callbacks
.onHideQuery(widget
);
357 s
.effects
.widgetHide
,
358 s
.effects
.effectDuration
,
361 if (s
.behaviour
.useCookies
) {
362 UpdateCookie(widgetId
, s
.cookies
.closeName
, s
);
364 if ($.isFunction(s
.callbacks
.onHide
)) {
365 s
.callbacks
.onHide(widget
);
376 /////////////////////////////
377 // Plugin default settings //
378 /////////////////////////////
381 * Plugin default settings
383 * This is the settings that plugin use in case that you not provide your
384 * own plugin settings. Also, you dont need to provide all the settings, but
385 * change only that you need: the plugin use the default settings that you
386 * not provided, and also the settings that you provide.
388 * In other words, the plugin merge your own settings with plugin defaults.
391 $.fn
.EasyWidgets
.defaults
= {
393 // Behaviour of the plugin
396 // Miliseconds delay between mousedown and drag start
399 // Miliseconds delay between mouseup and drag stop
402 // Determinme the opacity of Widget when start drag
405 // Cookies (require Cookie plugin) to store positions and states
409 // Some effects that can be apply sometimes
412 // Miliseconds for effects duration
415 // Can be none, slide or fade
419 widgetExtend
: 'none',
420 widgetCollapse
: 'none',
421 widgetOpenEdit
: 'none',
422 widgetCloseEdit
: 'none',
423 widgetCancelEdit
: 'none'
426 // Only for the optional cookie feature
435 // Cookie expiration time in days
438 // Store a secure cookie?
441 // Cookie name for close Widgets
442 closeName
: 'ew-close',
444 // Cookie name for disable all Widgets
445 disableName
: 'ew-disable',
447 // Cookie name for positined Widgets
448 positionName
: 'ew-position',
450 // Cookie name for collapsed Widgets
451 collapseName
: 'ew-collapse'
454 // Options name to use in the HTML markup
457 // To recognize a movable Widget
460 // To recognize a editable Widget
461 editable
: 'editable',
463 // To recognize a collapse Widget
464 collapse
: 'collapse',
466 // To recognize a removable Widget
467 removable
: 'removable',
469 // To recognize a collapsable Widget
470 collapsable
: 'collapsable',
472 // To recognize Widget that require confirmation when remove
473 closeConfirm
: 'closeconfirm'
476 // Callbacks functions
479 // When a Widget is added on demand, send the widget object and place ID
482 // When a editbox is closed, send the link and the widget objects
485 // When a Widget is show, send the widget object
488 // When a Widget is hide, send the widget object
491 // When a Widget is closed, send the link and the widget objects
494 // When Widgets are enabled using the appropiate public method
497 // When a Widget is extend, send the link and the widget objects
500 // When Widgets are disabled using the appropiate public method
503 // When a editbox is closed, send a ui object, see jQuery::sortable()
506 // When a Widget is collapse, send the link and the widget objects
509 // When a Widget is try to added, send the widget object and place ID
512 // When a editbox is try to close, send the link and the widget objects
515 // When a Widget is try to show, send the widget object
518 // When a Widget is try to hide, send the widget object
521 // When a Widget is try to close, send the link and the widget objects
524 // When a editbox is cancel (close), send the link and the widget objects
527 // When Widgets are enabled using the appropiate public method
530 // When a Widget is try to expand, send the link and the widget objects
533 // When Widgets are disabled using the appropiate public method
534 onDisableQuery
: null,
536 // When a Widget is try to expand, send the link and the widget objects
537 onCollapseQuery
: null,
539 // When a editbox is try to cancel, send the link and the widget objects
540 onCancelEditQuery
: null,
542 // When one Widget is repositioned, send the positions serialization
543 onChangePositions
: null,
545 // When Widgets need repositioned, get the serialization positions
546 onRefreshPositions
: null
549 // Selectors in HTML markup. All can be change by you, but not all is
550 // used in the HTML markup. For example, the "editLink" or "closeLink"
551 // is prepared by the plugin for every Widget.
554 // Container of a Widget (into another element that use as place)
555 // The container can be "div" or "li", for example. In the first case
556 // use another "div" as place, and a "ul" in the case of "li".
559 // Class identifier for a Widget
562 // Class identifier for a Widget place (parents of Widgets)
563 places
: '.widget-place',
565 // Class identifier for a Widget header (handle)
566 header
: '.widget-header',
568 // Class for the Widget header menu
569 widgetMenu
: '.widget-menu',
571 // Class identifier for Widget editboxes
572 editbox
: '.widget-editbox',
574 // Class identifier for Widget content
575 content
: '.widget-content',
577 // Class identifier for editbox close link or button, for example
578 closeEdit
: '.widget-close-editbox',
580 // Class identifier for a Widget edit link
581 editLink
: '.widget-editlink',
583 // Class identifier for a Widget close link
584 closeLink
: '.widget-closelink',
586 // Class identifier for Widgets placehoders
587 placeHolder
: 'widget-placeholder',
589 // Class identifier for a Widget collapse link
590 collapseLink
: '.widget-collapselink'
593 // To be translate the plugin into another languages
594 // But this variables can be used to show images instead
595 // links text, if you preffer. In this case set the HTML
596 // of the IMG elements.
599 // Widget edit link text
602 // Widget close link text
605 // Widget extend link text
606 extendText
: 'Extend',
608 // Widget collapse link text
609 collapseText
: 'Collapse',
611 // Widget cancel edit link text
612 cancelEditText
: 'Cancel',
614 // Widget edition link title
615 editTitle
: 'Edit this widget',
617 // Widget close link title
618 closeTitle
: 'Close this widget',
620 // Widget confirmation dialog message
621 confirmMsg
: 'Remove this widget?',
623 // Widget cancel edit link title
624 cancelEditTitle
: 'Cancel edition',
626 // Widget extend link title
627 extendTitle
: 'Extend this widget',
629 // Widget collapse link title
630 collapseTitle
: 'Collapse this widget'
634 //////////////////////////////
635 // Private plugin functions //
636 //////////////////////////////
639 * Initialize the widgets
641 * This private function is used in two methods of the plugin, the main
642 * public method: EasyWidgets() and AddEasyWidget() public method. In other
643 * words, this function is the main function of the plugin, and is use to
644 * initialize the widgets at a first time, and initialize the widgets added
647 * This function separate different things into other private functions:
648 * for more details see the related and used here plugin private functions.
651 * @param settings Array with the plugin settings
652 * @param widgetOnDemand Boolean Widget added on demand or not
653 * @return Boolean True in every case
656 function InitializeWidgets(
657 settings
, widgetOnDemand
) {
658 var b
= widgetOnDemand
;
659 var d
= $.fn
.EasyWidgets
.defaults
;
660 var s
= $.extend(true, d
, settings
);
661 $(s
.selectors
.widget
).each(function() {
662 PrepareWidgetBehaviour($(this), b
, s
);
664 RepositionedWidgets(s
);
665 MakeWidgetsSortables(s
);
666 CleanWidgetsCookies(s
, b
);
671 * Prepare the widgets behaviour
673 * This private function is called from another: InitializeWidgets()
674 * to prepare the behaviour of a found widget: append the widget menu
675 * if is needed, put into this the appropiate links, etc.
677 * As you can see, another private plugin functions are used here,
678 * we refer you to this functions for more details about this task.
679 * However, here is an important question about this function logical:
681 * This function can be use to deal with "normal" widgets and widgets
682 * added on demand. This function can be called to prepare certain
683 * widget that as been prepared when page onload: so, this widgets
684 * cannot be prepared again.
686 * To evit the duplication of the widget menus, basically, we find
687 * for this widget menu, and, if is empty, this widget need to be
688 * prepared, but, if this widget have a menu yet, cannot need to
691 * This condition only have sense when added widgets on demand, if
692 * not is the case, no one widget have a menu before prepared, so,
693 * are prepared here the first time that this function is called.
696 * @see InitializeWidgets()
697 * @see AddWidgetEditLink()
698 * @see AddWidgetRemoveLink()
699 * @see AddWidgetCollapseLink()
700 * @param widget jQuery object with a widget
701 * @param widgetOnDemand Boolean Widget added on demand or not
702 * @param settings Array with the plugin settings
703 * @return Boolean True if widget are prepared, False if is yet prepared
706 function PrepareWidgetBehaviour(widget
, widgetOnDemand
, settings
) {
708 var widgetMenu
= widget
.find(s
.selectors
.widgetMenu
);
709 if (widgetMenu
.html() == null) {
710 var widgetId
= widget
.attr('id');
711 var haveId
= ($.trim(widgetId
) != '');
712 widget
.find(s
.selectors
.editbox
).hide();
713 if (widgetOnDemand
&& haveId
&& s
.behaviour
.useCookies
) {
714 // Force this widget out of closed widgets cookie
715 // because in other case is possible that widget
716 // are added, but in fact not show in the document
717 CleanCookie(widgetId
, s
.cookies
.closeName
, s
);
719 if (!widgetOnDemand
&& haveId
&& s
.behaviour
.useCookies
720 && GetCookie(s
.cookies
.closeName
) != null) {
721 var cookieValue
= GetCookie(s
.cookies
.closeName
);
722 if (cookieValue
.indexOf(widgetId
) != -1) {
723 // But in case of not on demand widget, is possible
724 // to hide the widget, if is present in the appropiate
729 var menuWrap
= '<span class="' + s
.selectors
730 .widgetMenu
.replace(/\./, '') + '"></span>';
731 widget
.find(s
.selectors
.header
).append(menuWrap
);
732 // Now this menu is a valid wrap to add the links
733 widgetMenu
= widget
.find(s
.selectors
.widgetMenu
);
734 // The order of this function call is important
735 // because determine the order of links appear
736 AddWidgetCollapseLink(widget
, widgetMenu
, s
);
737 AddWidgetEditLink(widget
, widgetMenu
, s
);
738 AddWidgetRemoveLink(widget
, widgetMenu
, s
);
746 * Repositioned the widgets
748 * This private function is called from InitializeWidgets() and is used
749 * to repositioned the widgets in the appropiate places into the document.
751 * Some important question about this function is that the plugin can
752 * repositioned the widgets follow certain string, that containt the
753 * needed information.
755 * This string is produced in WidgetsPositionsChange() private function,
756 * and bassically contain the places IDs and the widgets IDs saved in
757 * a know format, that here we read to apply just later.
759 * Take a look at this: the mentioned string is saved in a cookie if you
760 * use the cookies feature of the plugin. But in any case the plugin send
761 * to you this string in the "onChangePositions()" callback.
763 * What is this? Suppose that you cannot use cookies, but still want to
764 * repositioned the widgets. So, you can get the refered string and save
765 * it in a database, for example.
767 * Then, just when this function is executed, you can provide this string
768 * returning it in the "onRefreshPositions()" plugin callback. Then, if you
769 * provide here a string that contain the widgets positions, the plugin use
770 * this string to repositioned the widgets.
772 * If you use the cookies plugin feature, the widget read the appropiate
773 * cookie, get the string previously saved (see WidgetsPositionsChange())
774 * and repositioned the widgets. Of course, if you not provide any string
775 * and also not use the cookies feature, the widgets cannot be positioned.
777 * Another thing more. You can see at WidgetsPositionsChange() how we
778 * conform the appropiate string, so, in this function we read the string
779 * based on the appropiate format. This string is like this:
781 * place-1=widget-1,widget-2|place-1=widget-3,widget-4
783 * Note one more thing: the order of the string is not casual: reflect the
784 * real order of the places and widgets in the document when the string is
785 * formed, so, the order of the widgets after this function is executed is
786 * the correct, because we follow the string as is.
789 * @see InitializeWidgets()
790 * @see PrepareSortablePlaces()
791 * @see WidgetsPositionsChange()
792 * @return Boolean True in every case
795 function RepositionedWidgets(settings
) {
798 if ($.isFunction(s
.callbacks
.onRefreshPositions
)) {
799 positions
= s
.callbacks
.onRefreshPositions();
801 // Only if not provide a string widget positions,
802 // use cookies and the appropiate cookie is not empty
803 if (($.trim(positions
) == '') && s
.behaviour
.useCookies
804 && GetCookie(s
.cookies
.positionName
) != null) {
805 // We get the widgets positions from the cookie
806 positions
= GetCookie(s
.cookies
.positionName
)
808 if ($.trim(positions
) != '') {
809 // Get the widgets places IDs and widgets IDs
810 var places
= positions
.split('|');
811 var totalPlaces
= places
.length
;
812 for (var i
= 0; i
< totalPlaces
; i
++) {
813 // Every part contain a place ID and possible widgets IDs
814 var place
= places
[i
].split('=');
815 // Validate (more or less) the format of the part that must
816 // contain two element: A place ID and one or more widgets IDs
817 if (place
.length
== 2) {
818 // Subpart one: the place ID
819 var placeSel
= '#' + place
[0];
820 // Subpart two: one or more widgets IDs
821 var widgets
= place
[1].split(',');
822 var totalWidgets
= widgets
.length
;
823 // Here we have a place and one or more widgets IDs
824 for (var j
= 0; j
< totalWidgets
; j
++) {
825 if ($.trim(widgets
[j
]) != '') {
826 // So, append every widget in the appropiate place
827 var widgetSel
= '#' + widgets
[j
];
828 $(widgetSel
).appendTo(placeSel
);
838 * Make widgets sortables
840 * This private function make found widgets as sortable items. This
841 * is called from another plugin private funtion: InitializeWidgets()
843 * As you can see, another private plugin functions are used here:
844 * we refer you to this functions for more details about this task.
847 * @see InitializeWidgets()
848 * @see GetSortableItems()
849 * @see PrepareSortableHeaders()
850 * @see PrepareSortablePlaces()
851 * @param settings Array with the plugin settings
852 * @return Boolean True in every case
855 function MakeWidgetsSortables(settings
) {
856 var sortables
= GetSortableItems(settings
);
857 PrepareSortableHeaders(sortables
, settings
);
858 PrepareSortablePlaces(sortables
, settings
);
863 * Find widgets and places as sortables items
865 * And return it. This function is called from MakeWidgetsSortables()
866 * to find the widgets and places as sortable items to work with this.
869 * @see MakeWidgetsSortables()
870 * @param settings Array with the plugin settings
871 * @return Boolean True in every case
874 function GetSortableItems(settings
) {
877 // Iterate all the widgets in document
878 $(s
.selectors
.widget
).each(function(count
) {
879 // When found a not movable widget
880 if (!$(this).hasClass(s
.options
.movable
)) {
881 // Try to get the widget ID
883 // And if not found prepare a special one
884 this.id
= 'fixed-widget-id-' + count
;
886 // Because this widget (fixed) not can be
887 // put as a sortable item, so, add to the
888 // fixed widgets selector, to use bellow
889 if (fixesSel
== '') {
890 fixesSel
+= '#' + this.id
;
892 fixesSel
+= ',' + '#' + this.id
;
896 // We prepare now the widget that cannot be put as
897 // sortable items, because are fixed widgets. We cannot
898 // use directly the fixed widgets selectors, because is
899 // no one fixed widget is found the selector is like this:
900 // :not(), that is, a emtpy "not selector", and this cause
901 // problems with jQuery version 1.3
903 if ($.trim(fixesSel
) == '') {
904 // So, if no fixed widgets are found, dont use the not selector
905 notFixes
= '> ' + s
.selectors
.container
;
907 // Use only in case that one or more fixed widgets are found
908 notFixes
= '> ' + s
.selectors
.container
+ ':not(' + fixesSel
+ ')';
910 // Its all. Return not fixed widgets and places as sortable items
911 return $(notFixes
, s
.selectors
.places
);
915 * Prepare sortables widgets headers
917 * This private function is called from another: MakeWidgetsSortables()
918 * and is used to prepare the widget headers as sortable items. Some
919 * behaviour is needed here, and the mayor part is based in the sortable
920 * feature of the jQuery UI library.
922 * In other words, this function prepare the widgets sortable headers
923 * to can be use as the widget handle, that the users can be use to move
924 * the widget into one place to another.
926 * For more information we refer you to the jQuery UI sortable feature
927 * documentation at this website for example: <http://www.api.jquery.com/>
930 * @see MakeWidgetsSortables()
931 * @param sortableItems jQuery object with found sortable items
932 * @param settings Array with the plugin settings
933 * @return Boolean True in every case
936 function PrepareSortableHeaders(sortableItems
, settings
) {
938 sortableItems
.find(s
.selectors
.header
).css({
940 }).mousedown(function(e
) {
941 var header
= $(this);
942 var widget
= header
.parent();
943 sortableItems
.css({ width
: '' });
945 width
: widget
.width() + 'px'
947 }).mouseup(function() {
948 var header
= $(this);
949 var widget
= header
.parent();
950 if (!widget
.hasClass('dragging')) {
951 widget
.css({ width
: '' });
953 $(s
.selectors
.places
).sortable('disable');
960 * Prepare sortables widgets places
962 * This private function is called from another: MakeWidgetsSortables()
963 * and is used to prepare the widget places as sortable items. Some
964 * behaviour is needed here, and the mayor part is based in the sortable
965 * feature of the jQuery UI library.
967 * For more information we refer you to the jQuery UI sortable feature
968 * documentation at this website for example: <http://www.api.jquery.com/>
971 * @see MakeWidgetsSortables()
972 * @see WidgetsPositionsChange()
973 * @param sortableItems jQuery object with found sortable items
974 * @param settings Array with the plugin settings
975 * @return Boolean True in every case
978 function PrepareSortablePlaces(sortableItems
, settings
) {
980 $(s
.selectors
.places
).sortable('destroy');
981 $(s
.selectors
.places
).sortable({
982 items
: sortableItems
,
983 containment
: 'document',
984 forcePlaceholderSize
: true,
985 handle
: s
.selectors
.header
,
986 delay
: s
.behaviour
.dragDelay
,
987 revert
: s
.behaviour
.dragRevert
,
988 opacity
: s
.behaviour
.dragOpacity
,
989 connectWith
: $(s
.selectors
.places
),
990 placeholder
: s
.selectors
.placeHolder
,
991 start: function(e
, ui
) {
992 $(ui
.helper
).addClass('dragging');
995 stop: function(e
, ui
) {
996 WidgetsPositionsChange(s
);
997 $(ui
.item
).css({ width
: '' });
998 $(ui
.item
).removeClass('dragging');
999 $(s
.selectors
.places
).sortable('enable');
1000 if ($.isFunction(s
.callbacks
.onDragStop
)) {
1001 s
.callbacks
.onDragStop(e
, ui
);
1006 // Ok, we take this place to disable widgets based on certain cookie
1007 if (s
.behaviour
.useCookies
&& (GetCookie(s
.cookies
.disableName
) == 1)) {
1008 $.fn
.DisableEasyWidgets(s
);
1014 * Handle the widgets positions changes
1016 * This function is called from the "stop" event of sortable widgets as
1017 * you can see here: PrepareSortablePlaces(), and is used to provide to
1018 * you of a string that contain the widgets positions in certain format.
1020 * This string structure is like:
1022 * place-1=widget-1,widget-2|place-1=widget-3,widget-4
1024 * See bellow how we conform this. You can save this string in a database
1025 * for example, and provide latter, when the "onRefreshPositions()" callback
1026 * is executed. So, the plugin use this string to repositioned the widgets
1027 * as you can see in RepositionedWidgets() function.
1030 * @see RepositionedWidgets()
1031 * @see PrepareSortablePlaces()
1032 * @param settings Array with the plugin settings
1033 * @return Boolean True in every case
1036 function WidgetsPositionsChange(settings
) {
1039 $(s
.selectors
.places
).each(function() {
1041 var place
= $(this);
1042 var places
= place
.attr('id') + '=';
1043 place
.children(s
.selectors
.widget
).each(function() {
1045 var widgetId
= widget
.id
;
1046 var haveId
= ($.trim(widgetId
) != '');
1048 if (widgets
== '') {
1049 widgets
+= widgetId
;
1051 widgets
+= ',' + widgetId
;
1056 if (positions
== '') {
1057 positions
+= places
;
1059 positions
+= '|' + places
;
1062 // You can save the positions string in a database, for example,
1063 // using the "onChangePositions()" plugin callback. So, when the
1064 // "onRefreshPositions()" callback is executed, you can retrieve
1065 // the string and returnt it: so the plugin use this string to
1066 // repositioned the widgets.
1067 if ($.isFunction(s
.callbacks
.onChangePositions
)) {
1068 s
.callbacks
.onChangePositions(positions
);
1070 // @todo Maybe we only put the positions on the cookie
1071 // if the user font use the "onChangePositions()" callback, because
1072 // at this time, ever if no use the cookie value (the user provide)
1073 // the positions from "onRefreshPositions()" callback) the positions
1074 // are saved in the cookie...
1075 if (s
.behaviour
.useCookies
) {
1076 // However, you need to use the cookies feature
1077 // to make possible the widgets repositioned
1078 if (GetCookie(s
.cookies
.positionName
) != positions
) {
1079 SetCookie(s
.cookies
.positionName
, positions
, s
);
1086 * Prepare a widget collapse menu link
1089 * @see PrepareWidgetBehaviour()
1090 * @param widget jQuery object with a widget encapsulation
1091 * @param widgetMenu jQuery object with a widget menu encapsulation
1092 * @param settings Array with the plugin settings
1093 * @return Boolean Truein every case
1096 function AddWidgetCollapseLink(widget
, widgetMenu
, settings
) {
1099 var widgetId
= widget
.attr('id');
1100 var haveId
= $.trim(widgetId
) != '';
1101 var content
= widget
.find(s
.selectors
.content
);
1102 if (widget
.hasClass(s
.options
.collapsable
)) {
1103 if (widget
.hasClass(s
.options
.collapse
)) {
1107 s
.selectors
.collapseLink
1112 s
.i18n
.collapseText
,
1113 s
.i18n
.collapseTitle
,
1114 s
.selectors
.collapseLink
1117 if (haveId
&& s
.behaviour
.useCookies
&&
1118 GetCookie(s
.cookies
.collapseName
) != null) {
1119 var cookieValue
= GetCookie(s
.cookies
.collapseName
);
1120 if (cookieValue
.indexOf(widgetId
) != -1) {
1124 s
.selectors
.collapseLink
1129 $(link
).mousedown(function(e
) {
1130 e
.stopPropagation();
1131 }).click(function() {
1132 var canExtend
= true;
1133 var canCollapse
= true;
1135 var widget
= link
.parents(s
.selectors
.widget
);
1136 var widgetId
= widget
.attr('id');
1137 var haveId
= $.trim(widgetId
) != '';
1138 var content
= widget
.find(s
.selectors
.content
);
1139 var contentVisible
= content
.css('display') != 'none';
1141 if (contentVisible
) {
1142 if ($.isFunction(s
.callbacks
.onCollapseQuery
)) {
1143 canCollapse
= s
.callbacks
.onCollapseQuery(link
, widget
);
1148 s
.effects
.widgetCollapse
,
1149 s
.effects
.effectDuration
,
1152 link
.html(s
.i18n
.extendText
);
1153 link
.attr('title', s
.i18n
.extendTitle
);
1154 if (s
.behaviour
.useCookies
&& widgetId
) {
1155 UpdateCookie(widgetId
, s
.cookies
.collapseName
, s
);
1157 if ($.isFunction(s
.callbacks
.onCollapse
)) {
1158 s
.callbacks
.onCollapse(link
, widget
);
1162 if ($.isFunction(s
.callbacks
.onExtendQuery
)) {
1163 canExtend
= s
.callbacks
.onExtendQuery(link
, widget
);
1166 link
.html(s
.i18n
.collapseText
);
1167 link
.attr('title', s
.i18n
.collapseTitle
);
1170 s
.effects
.widgetExtend
,
1171 s
.effects
.effectDuration
,
1174 if (haveId
&& s
.behaviour
.useCookies
) {
1175 CleanCookie(widgetId
, s
.cookies
.collapseName
, s
);
1177 if ($.isFunction(s
.callbacks
.onExtend
)) {
1178 s
.callbacks
.onExtend(link
, widget
);
1183 }).appendTo(widgetMenu
);
1189 * Prepare a widget edit menu link
1192 * @see PrepareWidgetBehaviour()
1193 * @param widget jQuery object with a widget encapsulation
1194 * @param widgetMenu jQuery object with a widget menu encapsulation
1195 * @param settings Array with the plugin settings
1196 * @return Boolean Truein every case
1199 function AddWidgetEditLink(widget
, widgetMenu
, settings
) {
1202 if (widget
.hasClass(s
.options
.editable
)) {
1206 s
.selectors
.editLink
1208 widget
.find(s
.selectors
.closeEdit
).click(function(e
) {
1210 var widget
= link
.parents(s
.selectors
.widget
);
1211 var editbox
= widget
.find(s
.selectors
.editbox
);
1212 var editLink
= widget
.find(s
.selectors
.editLink
);
1216 s
.effects
.widgetCloseEdit
,
1217 s
.effects
.effectDuration
,
1220 editLink
.html(s
.i18n
.editText
);
1221 editLink
.attr('title', s
.i18n
.editTitle
);
1224 $(link
).mousedown(function(e
) {
1225 e
.stopPropagation();
1226 }).click(function() {
1228 var canShow
= canHide
= true;
1229 var widget
= link
.parents(s
.selectors
.widget
);
1230 var editbox
= widget
.find(s
.selectors
.editbox
);
1231 var editboxVisible
= editbox
.css('display') != 'none';
1233 if (editboxVisible
) {
1234 if ($.isFunction(s
.callbacks
.onCancelEditQuery
)) {
1235 canHide
= s
.callbacks
.onCancelEditQuery(link
, widget
);
1240 s
.effects
.widgetCancelEdit
,
1241 s
.effects
.effectDuration
,
1244 link
.html(s
.i18n
.editText
);
1245 link
.attr('title', s
.i18n
.editTitle
);
1246 if ($.isFunction(s
.callbacks
.onCancelEdit
)) {
1247 s
.callbacks
.onCancelEdit(link
, widget
);
1251 if ($.isFunction(s
.callbacks
.onEditQuery
)) {
1252 canShow
= s
.callbacks
.onEditQuery(link
, widget
);
1255 link
.html(s
.i18n
.cancelEditText
);
1256 link
.attr('title', s
.i18n
.cancelEditTitle
);
1259 s
.effects
.widgetOpenEdit
,
1260 s
.effects
.effectDuration
,
1263 if ($.isFunction(s
.callbacks
.onEdit
)) {
1264 s
.callbacks
.onEdit(link
, widget
);
1269 }).appendTo(widgetMenu
);
1275 * Prepare a widget remove menu link
1278 * @see PrepareWidgetBehaviour()
1279 * @param widget jQuery object with a widget encapsulation
1280 * @param widgetMenu jQuery object with a widget menu encapsulation
1281 * @param settings Array with the plugin settings
1282 * @return Boolean Truein every case
1285 function AddWidgetRemoveLink(widget
, widgetMenu
, settings
) {
1288 if (widget
.hasClass(s
.options
.removable
)) {
1292 s
.selectors
.closeLink
1294 $(link
).mousedown(function(e
) {
1295 e
.stopPropagation();
1296 }).click(function() {
1298 var canRemove
= true;
1299 var widget
= link
.parents(s
.selectors
.widget
);
1300 var widgetId
= widget
.attr('id');
1301 var haveId
= ($.trim(widgetId
) != '');
1303 if ($.isFunction(s
.callbacks
.onCloseQuery
)) {
1304 canRemove
= s
.callbacks
.onCloseQuery(link
, widget
);
1307 if (!widget
.hasClass(s
.options
.closeConfirm
)
1308 || confirm(s
.i18n
.confirmMsg
)) {
1309 if (haveId
&& s
.behaviour
.useCookies
) {
1310 UpdateCookie(widgetId
, s
.cookies
.closeName
, s
);
1314 s
.effects
.widgetClose
,
1315 s
.effects
.effectDuration
,
1318 if ($.isFunction(s
.callbacks
.onClose
)) {
1319 s
.callbacks
.onClose(link
, widget
);
1324 }).appendTo(widgetMenu
);
1330 * Clean widgets related cookies
1332 * This private function is called from InitializeWidgets() and used to
1333 * clean certain widgets related cookies. What is this? Well, basically
1334 * here we find for no more used widgets IDs into the appropiate cookies
1335 * values, and remove from this.
1337 * Why? Because in this form the related cookies ever still clean. ;)
1338 * This cookies are the "closed widgets" and "collapses widgets" cookies,
1339 * that store widgets IDs in the same way: separated by commas. So, find
1340 * widgets IDs that in fact not found in the document, and remove from the
1341 * appropiate cookie value, remainded the rest of the widgets IDs.
1343 * Because this function is called from the main plugin method, called
1344 * itself every time that a page that contain widgets is refresh, or when
1345 * add widgets on demand, we only try to clean the cookies in a "random"
1346 * mode, because, finally, is not problem that a cookie contain widgets
1347 * IDs that dont exists.
1349 * So, to save resources, we clean the cookies only in no on demand widgets,
1350 * and only in some "random" times, as you can see in the bellow code.
1353 * @see InitializeWidgets()
1354 * @param settings Array with the plugin settings
1355 * @param widgetOnDemand Boolean Depend if deal with on demand widget or not
1356 * @return Boolean True in every case
1359 function CleanWidgetsCookies(settings
, widgetOnDemand
) {
1361 var cleanCookies
= !widgetOnDemand
&& s
.behaviour
.useCookies
1362 && (Math
.ceil(Math
.random() * 3) == 1);
1365 var cookies
= new Array(
1366 s
.cookies
.closeName
,
1367 s
.cookies
.collapseName
1369 var cookiesLen
= cookies
.length
;
1370 var widgetsIds
= new Array();
1371 $(s
.selectors
.widget
).each(function(count
) {
1372 var widgetId
= $(this).attr('id');
1373 if ($.trim(widgetId
) != '') {
1374 widgetsIds
[count
] = widgetId
;
1377 for (i
= 0; i
< cookiesLen
; i
++) {
1378 if (GetCookie(cookies
[i
])) {
1380 var cleanValue
= '';
1381 var storedValue
= GetCookie(cookies
[i
]).split(',');
1382 var storedWidgets
= storedValue
.length
;
1383 for (j
= 0; j
< storedWidgets
; j
++) {
1384 widgetId
= $.trim(storedValue
[j
]);
1385 if ($.inArray(widgetId
, widgetsIds
) != -1) {
1386 if ($.trim(cleanValue
) == '') {
1387 cleanValue
+= widgetId
;
1389 cleanValue
+= ',' + widgetId
;
1393 SetCookie(cookies
[i
], cleanValue
, s
);
1401 * Get a specific cookie value
1403 * This function is based in jQuery Cookie plugin by Klaus Hartl
1406 * @param name String with the cookie name
1407 * @return Null|String Cookie value or nothing
1410 function GetCookie(name
) {
1412 if (document
.cookie
&& $.trim(document
.cookie
) != '') {
1413 var cookies
= document
.cookie
.split(';');
1414 var cookiesLen
= cookies
.length
;
1415 if (cookiesLen
> 0) {
1416 for (var i
= 0; i
< cookiesLen
; i
++) {
1417 var cookie
= $.trim(cookies
[i
]);
1418 if (cookie
.substring(0, name
.length
+ 1) == (name
+ '=')) {
1419 result
= decodeURIComponent(cookie
.substring(name
.length
+ 1));
1429 * Set a specific cookie value
1431 * This function is based in jQuery Cookie plugin by Klaus Hartl
1434 * @param name String with the cookie name
1435 * @param value String with the cookie value
1436 * @param settings Array with plugin settings to use
1437 * @return Boolean True in every case
1440 function SetCookie(name
, value
, settings
) {
1443 var nType
= 'number';
1444 if (s
.cookies
.expires
&& (typeof s
.cookies
.expires
1445 == nType
) || s
.cookies
.expires
.toUTCString
) {
1447 if (typeof s
.cookies
.expires
== nType
) {
1449 date
.setTime(date
.getTime() + (s
.cookies
.expires
* 24 * 60 * 60 * 1000));
1451 date
= s
.cookies
.expires
;
1453 // use expires attribute, max-age is not supported by IE
1454 expires
= '; expires=' + date
.toUTCString();
1456 var path
= s
.cookies
.path
? '; path=' + s
.cookies
.path
: '';
1457 var domain
= s
.cookies
.domain
? '; domain=' + s
.cookies
.domain
: '';
1458 var secure
= s
.cookies
.secure
? '; secure' : '';
1459 document
.cookie
= [name
, '=', encodeURIComponent(value
),
1460 expires
, path
, domain
, secure
].join('');
1465 * Clean a Widget Id from a cookie
1467 * We use this in some places, so, centralize here. We clean certain
1468 * related cookie: two of the plugins related cookies using the same
1469 * structure to save their data, and can be clean in the same way.
1471 * A string with comma separated Widgets IDs is stored in this cookies,
1472 * and "clean a cookie" want to say: remove certain Widget ID from this
1473 * cookie, because this widget is now visible or extended.
1476 * @param widgetId String with a Widget identifier
1477 * @param cookieName String with the cookie name
1478 * @param settings Array with plugin settings to use
1479 * @return Boolean True in every case
1482 function CleanCookie(widgetId
, cookieName
, settings
) {
1483 var value
= GetCookie(cookieName
);
1484 if (value
!= null) {
1485 if (value
.indexOf(widgetId
) != -1) {
1486 value
= value
.replace(',' + widgetId
, '');
1487 value
= value
.replace(widgetId
+ ',', '');
1488 value
= value
.replace(widgetId
, '');
1490 SetCookie(cookieName
, value
, settings
);
1496 * Update a Widget Id from a cookie
1498 * We use this in some places, so, centralize here. We update certain
1499 * related cookie: two of the plugins related cookies using the same
1500 * structure to save their data, and can be update in the same way.
1502 * A string with comma separated Widgets IDs is stored in this cookies,
1503 * and "update a cookie" want to say: put certain Widget ID in this
1504 * cookie, because this widget is now closed or collapsed.
1507 * @param widgetId String with a Widget identifier
1508 * @param cookieName String with the cookie name
1509 * @param settings Array with plugin settings to use
1510 * @return Boolean True in every case
1513 function UpdateCookie(widgetId
, cookieName
, settings
) {
1514 var value
= GetCookie(cookieName
);
1515 if (value
== null) {
1517 } else if (value
.indexOf(widgetId
) == -1) {
1518 value
= value
+ ',' + widgetId
;
1520 SetCookie(cookieName
, value
, settings
);
1525 * Auxiliar function to prepare Widgets header menu links.
1528 * @param text Link text
1529 * @param title Link title
1530 * @param aClass CSS class (behaviour) of link
1531 * @return String HTML of the link
1534 function MenuLink(text
, title
, aClass
) {
1535 var l
= '<a href="#" title="TITLE" class="CLASS">TEXT</a>';
1536 l
= l
.replace(/TEXT/g, text
);
1537 l
= l
.replace(/TITLE/g, title
);
1538 l
= l
.replace(/CLASS/g, aClass
.replace(/\./, ''));
1543 * Auxiliar function to show, hide and apply effects.
1546 * @param jqObj jQuery object to apply the effect and show or hide
1547 * @param effect String that identifier what effect must be applied
1548 * @param duration Miliseconds to the effect duration
1549 * @param show Boolean True if want to show the object, False to be hide
1550 * @return Boolean True in every case
1553 function ApplyEffect(jqObj
, effect
, duration
, show
) {
1560 } else if (effect
== f
) {
1561 jqObj
.fadeOut(duration
);
1562 } else if (effect
== s
) {
1563 jqObj
.slideUp(duration
);
1568 } else if (effect
== f
) {
1569 jqObj
.fadeIn(duration
);
1570 } else if (effect
== s
) {
1571 jqObj
.slideDown(duration
);