Commit 709d0a059e3d6844bea61e2cba44481407774257

Authored by Julien Verneuil
1 parent 9952c7cb

added jquery animate functionality

web/jQuery/CXM_jquery_animate.anubis 0 → 100644
  1 + Allow to animate the style of a HTML element on a certain action (hover, click etc).
  2 +
  3 + You can use pre-built animation or craft your own.
  4 +
  5 + Note:
  6 +
  7 + Colors related animatable styles are only available if jQuery-ui is used.
  8 +
  9 +
  10 + Built-in animations
  11 +
  12 + * fade_out
  13 +
  14 + * fade_in
  15 +
  16 + * size_on_hover
  17 + Animate the size of the element when hovering it to a specified width / height target value,
  18 + the element return to its initial size (if there is any) when the mouse is not hovering it anymore.
  19 +
  20 + Example:
  21 + jquery_animate
  22 + (
  23 + element(htmlId("my_element")),
  24 + size_on_hover(32, 32, 1000, 1000)
  25 + )
  26 +
  27 + * custom
  28 + Can be used to craft your own animation.
  29 +
  30 + - You can make simple animation like this (transition the background color to green on a click):
  31 +
  32 + jquery_animate
  33 + (
  34 + element(htmlId("my_element")),
  35 + custom(onclick, background_color(rgb(0, 255, 0)), linear, 1000)
  36 + )
  37 +
  38 + - Or you can make something more complex which use all capabilities, like this custom made "size_on_hover" animation
  39 +
  40 + jquery_animate
  41 + (
  42 + element(htmlId("my_element")),
  43 + [
  44 + custom(id("_over"), onmouseover, [ id("_out") ], [width(64), height(64)], easeOutBack, 1000),
  45 + custom(
  46 + id("_out"), // id used to identify this animation
  47 + onmouseout, // animation triggering html event
  48 + [ id("_hover")], // a list of ids, used to stop others animations to play when this one is triggered
  49 + [], // empty list of styles mean it will animate back to the initial state of the element
  50 + easeOutElastic, // easing equation
  51 + 1000 // duration
  52 + )
  53 + ]
  54 + )
  55 +
  56 + Which is similar to:
  57 + size_on_hover(64, 64, 1000, 1000)
  58 +
  59 + TODO:
  60 + Choice of an animation target using a selector
  61 + Chained animation
  62 +
  63 + Author: Julien Verneuil (25/04/2015)
  64 +
  65 +read tools/basis.anubis
  66 +read tools/printable_tree.anubis
  67 +
  68 +read calexium_lib/web/CXM_making_a_web_site.anubis
  69 +read calexium_lib/web/CXM_json.anubis
  70 +read calexium_lib/web/CXM_jquery.anubis
  71 +read calexium_lib/web/jQuery/CXM_jquery_easing.anubis
  72 +
  73 +read calexium_lib/web/CXM_style_tools.anubis
  74 +read calexium_lib/web/js_tools.anubis
  75 +
  76 +public type AnimatableCSSStyle:
  77 + width(Int value),
  78 + height(Int value),
  79 + max_width(Int value),
  80 + max_height(Int value),
  81 + min_width(Int value),
  82 + min_height(Int value),
  83 + outline_width(Int value),
  84 + border_width(Int value),
  85 + border_top_width(Int value),
  86 + border_right_width(Int value),
  87 + border_bottom_width(Int value),
  88 + border_left_width(Int value),
  89 + top(Int value),
  90 + right(Int value),
  91 + left(Int value),
  92 + bottom(Int value),
  93 + margin_top(Int value),
  94 + margin_right(Int value),
  95 + margin_left(Int value),
  96 + margin_bottom(Int value),
  97 + padding_top(Int value),
  98 + padding_right(Int value),
  99 + padding_left(Int value),
  100 + padding_bottom(Int value),
  101 + font_size(Int value),
  102 + line_height(Int value),
  103 + letter_spacing(Int value),
  104 + border_spacing(Int value),
  105 + text_indent(Int value),
  106 + word_spacing(Int value),
  107 + z_index(Int value),
  108 + outline_color(RGBA color),
  109 + border_color(RGBA color),
  110 + border_top_color(RGBA color),
  111 + border_right_color(RGBA color),
  112 + border_bottom_color(RGBA color),
  113 + border_left_color(RGBA color),
  114 + background_color(RGBA color),
  115 + color(RGBA color),
  116 + opacity(Float value).
  117 +
  118 +public type JQueryAnimationId:
  119 + id(String id).
  120 +
  121 +public type JQueryAnimation:
  122 + fade_out(HtmlEvents trigger, JQueryEasing type, Int duration),
  123 + fade_in(HtmlEvents trigger, JQueryEasing type, Int duration),
  124 + size_on_hover(Int width, Int height, Int duration_ms_on, Int duration_ms_out),
  125 + custom(HtmlEvents trigger, List(AnimatableCSSStyle) styles, JQueryEasing easing_type, Int duration_ms),
  126 + custom(HtmlEvents trigger, List(JQueryAnimationId) stop_anims_id, List(AnimatableCSSStyle) styles, JQueryEasing easing_type, Int duration_ms),
  127 + custom(JQueryAnimationId id, HtmlEvents trigger, List(JQueryAnimationId) stop_anims_id, List(AnimatableCSSStyle) styles, JQueryEasing easing_type, Int duration_ms),
  128 + custom(JQueryAnimationId id, HtmlEvents trigger, List(AnimatableCSSStyle) styles, JQueryEasing easing_type, Int duration_ms).
  129 +
  130 +type JQueryFormattedAnimation:
  131 + formatted_animation(String id, String trigger_name, JsonValue stop_anim_id, JsonValue css_props, JsonValue options).
  132 +
  133 +define HTML_Head_Tag required_js = js(js_file("js/cxm/cxm_jquery_animate.js")).
  134 +
  135 +define String js_anim_function_name = "CalexiumToolBox.CXM_Animate.animate".
  136 +
  137 +define String
  138 + format_html_event_to_js
  139 + (
  140 + HtmlEvents ev
  141 + ) =
  142 + if ev is
  143 + {
  144 + onchange then "change",
  145 + onsubmit then "submit",
  146 + onreset then "reset",
  147 + onselect then "select",
  148 + onblur then "blur",
  149 + onfocus then "focus",
  150 + onkeydown then "keydown"
  151 + onkeypress then "keypress",
  152 + onkeyup then "keyup",
  153 + onclick then "click",
  154 + ondblclick then "dblclick",
  155 + onmousedown then "mousedown",
  156 + onmousemove then "mousemove",
  157 + onmouseout then "mouseout",
  158 + onmouseover then "mouseover",
  159 + onmouseup then "mouseup"
  160 + }.
  161 +
  162 +define List(JsonMember)
  163 + animatables_to_json_members
  164 + (
  165 + List(AnimatableCSSStyle) styles,
  166 + List(JsonMember) json_members
  167 + ) =
  168 + if styles is
  169 + {
  170 + [ ] then
  171 + json_members,
  172 +
  173 + [ animatable_style . t ] then
  174 + with json_member =
  175 + if animatable_style is
  176 + {
  177 + width(value) then json_member("width", json_int(value)),
  178 + height(value) then json_member("height", json_int(value)),
  179 + max_width(value) then json_member("max-width", json_int(value)),
  180 + max_height(value) then json_member("max-height", json_int(value)),
  181 + min_width(value) then json_member("min-width", json_int(value)),
  182 + min_height(value) then json_member("min-height", json_int(value)),
  183 + outline_width(value) then json_member("outline-width", json_int(value)),
  184 + border_width(value) then json_member("border-width", json_int(value)),
  185 + border_top_width(value) then json_member("border-top-width", json_int(value)),
  186 + border_right_width(value) then json_member("border-right-width", json_int(value)),
  187 + border_bottom_width(value) then json_member("border-bottom-width", json_int(value)),
  188 + border_left_width(value) then json_member("border-left-width", json_int(value)),
  189 + top(value) then json_member("top", json_int(value)),
  190 + right(value) then json_member("right", json_int(value)),
  191 + left(value) then json_member("left", json_int(value)),
  192 + bottom(value) then json_member("bottom", json_int(value)),
  193 + margin_top(value) then json_member("margin-top", json_int(value)),
  194 + margin_right(value) then json_member("margin-right", json_int(value)),
  195 + margin_left(value) then json_member("margin-left", json_int(value)),
  196 + margin_bottom(value) then json_member("margin-bottom", json_int(value)),
  197 + padding_top(value) then json_member("padding-top", json_int(value)),
  198 + padding_right(value) then json_member("padding-right", json_int(value)),
  199 + padding_left(value) then json_member("padding-left", json_int(value)),
  200 + padding_bottom(value) then json_member("padding-bottom", json_int(value)),
  201 + font_size(value) then json_member("font-size", json_int(value)),
  202 + line_height(value) then json_member("line-height", json_int(value)),
  203 + letter_spacing(value) then json_member("letter-spacing", json_int(value)),
  204 + border_spacing(value) then json_member("border-spacing", json_int(value)),
  205 + text_indent(value) then json_member("text-indent", json_int(value)),
  206 + word_spacing(value) then json_member("word-spacing", json_int(value)),
  207 + z_index(value) then json_member("z-index", json_int(value)),
  208 + outline_color(color) then json_member("outline-color", json_string(format_rgba_to_style_color(color))),
  209 + border_color(color) then json_member("border-color", json_string(format_rgba_to_style_color(color))),
  210 + border_top_color(color) then json_member("border-top-color", json_string(format_rgba_to_style_color(color))),
  211 + border_right_color(color) then json_member("border-right-color", json_string(format_rgba_to_style_color(color))),
  212 + border_bottom_color(color) then json_member("border-bottom-color", json_string(format_rgba_to_style_color(color))),
  213 + border_left_color(color) then json_member("border-left-color", json_string(format_rgba_to_style_color(color))),
  214 + background_color(color) then json_member("background-color", json_string(format_rgba_to_style_color(color))),
  215 + color(color) then json_member("color", json_string(format_rgba_to_style_color(color))),
  216 + opacity(value) then json_member("opacity", json_float(value, 8))
  217 + },
  218 +
  219 + animatables_to_json_members(t, [ json_member . json_members])
  220 + }.
  221 +
  222 +define List(JsonMember)
  223 + animatables_to_json_members
  224 + (
  225 + List(AnimatableCSSStyle) styles
  226 + ) =
  227 + animatables_to_json_members(styles, [ ]).
  228 +
  229 +define JQueryFormattedAnimation
  230 + format_animation
  231 + (
  232 + JQueryAnimationId id,
  233 + HtmlEvents trigger,
  234 + List(JQueryAnimationId) stop_anims_id,
  235 + List(AnimatableCSSStyle) styles,
  236 + JQueryEasing type,
  237 + Int duration_ms
  238 + ) =
  239 + with css_props_as_json_members = animatables_to_json_members(styles),
  240 + easing_str = format_easing(type),
  241 + trigger_str = format_html_event_to_js(trigger),
  242 +
  243 + id_str = if id is id(id_str) then id_str,
  244 +
  245 + formatted_animation(
  246 + id_str,
  247 + trigger_str,
  248 + json_array(
  249 + map((JQueryAnimationId e) |-> if e is { id(id_str) then json_string(id_str) }, stop_anims_id)
  250 + ),
  251 + json_object(css_props_as_json_members),
  252 + json_object(
  253 + [
  254 + json_member("duration", json_int(duration_ms)),
  255 + json_member("easing", json_string(easing_str))
  256 + ]
  257 + )
  258 + ).
  259 +
  260 +define JQueryFormattedAnimation
  261 + format_animation
  262 + (
  263 + HtmlEvents trigger,
  264 + List(JQueryAnimationId) stop_anims_id,
  265 + List(AnimatableCSSStyle) styles,
  266 + JQueryEasing type,
  267 + Int duration_ms
  268 + ) =
  269 + format_animation(id(""), trigger, stop_anims_id, styles, type, duration_ms).
  270 +
  271 +define JQueryFormattedAnimation
  272 + format_animation
  273 + (
  274 + JQueryAnimationId id,
  275 + HtmlEvents trigger,
  276 + List(AnimatableCSSStyle) styles,
  277 + JQueryEasing type,
  278 + Int duration_ms
  279 + ) =
  280 + format_animation(id, trigger, [ ], styles, type, duration_ms).
  281 +
  282 +define JQueryFormattedAnimation
  283 + format_animation
  284 + (
  285 + HtmlEvents trigger,
  286 + List(AnimatableCSSStyle) styles,
  287 + JQueryEasing type,
  288 + Int duration_ms
  289 + ) =
  290 + format_animation(id(""), trigger, [ ], styles, type, duration_ms).
  291 +
  292 +define List(JQueryFormattedAnimation)
  293 + format_animation
  294 + (
  295 + JQueryAnimation anim_type
  296 + ) =
  297 + if anim_type is
  298 + {
  299 + fade_out(trigger, easing, duration) then
  300 + [ format_animation(trigger, [opacity(0)], easing, duration) ],
  301 +
  302 + fade_in(trigger, easing, duration) then
  303 + [ format_animation(trigger, [opacity(1)], easing, duration) ],
  304 +
  305 + size_on_hover(w, h, d_in, d_out) then
  306 + [
  307 + format_animation(id("_over"), onmouseover, [ id("_out") ], [width(w), height(h)], easeOutBack, d_in),
  308 + format_animation(id("_out"), onmouseout , [ id("_over") ], [] , easeOutElastic, d_out)
  309 + ],
  310 +
  311 + custom(trigger, styles, easing_type, duration_ms) then
  312 + [ format_animation(trigger, styles, easing_type, duration_ms) ]
  313 +
  314 + custom(trigger, stop_anims_id, styles, easing_type, duration_ms) then
  315 + [ format_animation(trigger, stop_anims_id, styles, easing_type, duration_ms) ]
  316 +
  317 + custom(id,trigger,stop_anims_id,styles,easing_type,duration_ms) then
  318 + [ format_animation(id, trigger, stop_anims_id, styles, easing_type, duration_ms) ]
  319 +
  320 + custom(id,trigger,styles,easing_type,duration_ms) then
  321 + [ format_animation(id, trigger, styles, easing_type, duration_ms) ]
  322 + }.
  323 +
  324 +define List(JQueryFormattedAnimation)
  325 + format_animations
  326 + (
  327 + List(JQueryFormattedAnimation) formatted_anims,
  328 + List(JQueryAnimation) anims
  329 + ) =
  330 + if anims is
  331 + {
  332 + [ ] then formatted_anims,
  333 +
  334 + [ anim . t ] then
  335 + format_animations(formatted_anims + format_animation(anim), t)
  336 + }.
  337 +
  338 +define List(JsonValue)
  339 + generate_js
  340 + (
  341 + List(JQueryFormattedAnimation) formatted_anims,
  342 + List(JsonValue) anim_objects
  343 + ) =
  344 + if formatted_anims is
  345 + {
  346 + [ ] then anim_objects,
  347 +
  348 + [ formatted_anim . t ] then
  349 + if formatted_anim is
  350 + {
  351 + formatted_animation(id_str, trigger_str, stop_anims_id_as_json_array, css_props, options) then
  352 + generate_js(
  353 + t,
  354 + [
  355 + json_object(
  356 + [
  357 + json_member("id", id_str),
  358 + json_member("event", trigger_str),
  359 + json_member("stop_anims_id", stop_anims_id_as_json_array),
  360 + json_member("props", css_props),
  361 + json_member("options", options)
  362 + ]
  363 + )
  364 + . anim_objects
  365 + ]
  366 + )
  367 + }
  368 + }.
  369 +
  370 +public define List(HTML_Head_Tag)
  371 + generate_head_tags
  372 + (
  373 + JQuerySelector jq_selector,
  374 + List(JQueryAnimation) anims
  375 + ) =
  376 + [
  377 + required_js,
  378 + js_inline(
  379 + jquery_ready(
  380 + format_js_function_call(
  381 + js_anim_function_name,
  382 + [
  383 + format_jquery_selector(jq_selector),
  384 + to_javascript(
  385 + json_array(
  386 + generate_js(
  387 + format_animations([ ], anims),
  388 + [ ]
  389 + )
  390 + )
  391 + )
  392 + ]
  393 + )
  394 + )
  395 + )
  396 + ].
  397 +
  398 +public define List(HTML_Head_Tag)
  399 + jquery_animate
  400 + (
  401 + JQuerySelector jq_selector,
  402 + List(JQueryAnimation) anims
  403 + ) =
  404 + generate_head_tags(jq_selector, anims).
  405 +
  406 +public define HTML_Partial_Content
  407 + jquery_animate
  408 + (
  409 + JQuerySelector jq_selector,
  410 + List(JQueryAnimation) anims
  411 + ) =
  412 + partial_content(generate_head_tags(jq_selector, anims), literal("")).
  413 +
  414 +public define List(HTML_Head_Tag)
  415 + jquery_animate
  416 + (
  417 + JQuerySelector jq_selector,
  418 + JQueryAnimation anim_type
  419 + ) =
  420 + generate_head_tags(jq_selector, [ anim_type ]).
  421 +
  422 +public define HTML_Partial_Content
  423 + jquery_animate
  424 + (
  425 + JQuerySelector jq_selector,
  426 + JQueryAnimation anim_type
  427 + ) =
  428 + partial_content(generate_head_tags(jq_selector, [ anim_type ]), literal("")).
  429 +
web/js/cxm_jquery_animate.js 0 → 100644
  1 +/*
  2 + Animation of HTML elements style.
  3 +
  4 + Requirement:
  5 + jquery
  6 + jquery-ui (if you want to use advanced animating functions, ie: easing)
  7 +
  8 + Usage:
  9 + CalexiumToolBox.CXM_Animate.animate(selector, trigger_type, css_props, options, second_options);
  10 +
  11 + Arguments:
  12 + - selector
  13 + JQuery selector (string), animation and event will be applied to HTML elements matched by the selector.
  14 +
  15 + * Example:
  16 +
  17 + "#element_id"
  18 + or
  19 + ".class_name"
  20 +
  21 + - anims
  22 + Array of animations object
  23 +
  24 + Example:
  25 + [
  26 + {
  27 + id: "my_animation",
  28 + event: "mouseover"
  29 + stop_anims_id: [],
  30 + props: { width: 64, height: 64 },
  31 + options: { easing: "linear", duration: 2000 }
  32 + }
  33 + }
  34 +
  35 + Note:
  36 + Options properties are the same as the jquery "animate" method options.
  37 +*/
  38 +
  39 +$(document).ready(function () {
  40 + if (window.CalexiumToolBox === undefined) {
  41 + CalexiumToolBox = {};
  42 + }
  43 +
  44 + if (CalexiumToolBox.CXM_Animate === undefined) {
  45 + CalexiumToolBox.CXM_Animate = {
  46 + animate: null // see below
  47 + };
  48 + }
  49 +
  50 + CalexiumToolBox.CXM_Animate.animate = function (selector, anims) {
  51 + $(selector).each(function() {
  52 + var elem = $(this),
  53 +
  54 + grouped_anims = {
  55 +
  56 + },
  57 +
  58 + initial_css_props = {};;
  59 +
  60 + // group/register anims by events
  61 + $(anims).each(function (index, anim) {
  62 + var anim_group = grouped_anims[anim.event];
  63 +
  64 + if (anim_group === undefined) {
  65 + anim_group = grouped_anims[anim.event] = [];
  66 + }
  67 +
  68 + anim_group.push(anim);
  69 + });
  70 +
  71 + // iterate over all props of each anims and store the initial state of each css props of the element
  72 + // this is done only once for the group of anims and it happen only if one anim props is empty which mean it animate back to element initial state at initialization
  73 + for (i = 0; i < anims.length; i += 1) {
  74 + if (jQuery.isEmptyObject(anims[i].props) && jQuery.isEmptyObject(initial_css_props)) {
  75 + for (j = 0; j < anims.length; j += 1) {
  76 + $.each(anims[j].props, function (key, value) {
  77 + initial_css_props[key] = elem.css(key).replace('px', '');
  78 + });
  79 + }
  80 +
  81 + anims[i].props = initial_css_props;
  82 +
  83 + break;
  84 + }
  85 + }
  86 +
  87 + // now for each event groups, bind the event
  88 + $.each(grouped_anims, function (key, anims) {
  89 + elem.bind(key,
  90 + function() {
  91 + var anim_object, options,
  92 + id, i, j;
  93 +
  94 + // setup each animations
  95 + for (i = 0; i < anims.length; i += 1) {
  96 + anim_object = anims[i];
  97 + options = anim_object.options,
  98 + stop_anims_id = anim_object.stop_anims_id;
  99 +
  100 + // stop if needed specific anims determined by a list of ids
  101 + if (stop_anims_id !== undefined) {
  102 + for (id = 0; id < stop_anims_id.length; id += 1) {
  103 + elem.stop(stop_anims_id[id], true);
  104 + }
  105 + }
  106 +
  107 + options.queue = anim_object.id;
  108 +
  109 + elem.animate(anim_object.props, options).dequeue(anim_object.id);
  110 + }
  111 + }
  112 + );
  113 + });
  114 + });
  115 + };
  116 +});