{"id":20590024,"url":"https://github.com/doist/ice","last_synced_at":"2025-04-14T22:24:36.955Z","repository":{"id":22243483,"uuid":"25576888","full_name":"Doist/ICE","owner":"Doist","description":"The Lightweight JavaScript library","archived":false,"fork":false,"pushed_at":"2024-04-01T17:43:45.000Z","size":28,"stargazers_count":34,"open_issues_count":1,"forks_count":2,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-28T10:21:44.957Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Doist.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2014-10-22T11:03:08.000Z","updated_at":"2024-05-27T07:47:39.000Z","dependencies_parsed_at":"2024-11-16T07:33:50.166Z","dependency_job_id":"5cb13769-be6b-4096-84bc-0a9523891b4b","html_url":"https://github.com/Doist/ICE","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Doist%2FICE","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Doist%2FICE/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Doist%2FICE/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Doist%2FICE/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Doist","download_url":"https://codeload.github.com/Doist/ICE/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248970169,"owners_count":21191386,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-16T07:33:39.308Z","updated_at":"2025-04-14T22:24:36.927Z","avatar_url":"https://github.com/Doist.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"```\n_|_|_|    _|_|_|  _|_|_|_|  \n  _|    _|        _|        \n  _|    _|        _|_|_|    \n  _|    _|        _|        \n_|_|_|    _|_|_|  _|_|_|_|  \n                            \nICE - Lightweight JavaScript library\n```\n    \nICE features:\n* Small footprint (65KB uncompressed)\n* Mature - used on Todoist.com since 2007\n* Unified things that work in all the modern browsers (IE 7+)\n* Functional programming\n* DOM helpers\n* Array helpers\n* Element store\n* Powerful and easy to use requests\n* Deferred abstraction\n* Class abstraction\n* Effects\n* Drag and drop helpers\n* and a lot more...\n\nExample of ICE:\n```javascript\n// Requests\nfunction loadUsers() {\n    var req = $requestJSON('/users/get')\n\n    req.addCallback(function(users) {\n        var user_holder = $('user_holder')\n        $map(users, function(user) {\n            var li = LI({c: 'user'}, user.name)\n            $AEV(li, 'click', UserController.click)\n            $add(user_holder, li)\n        })\n    })\n\n    req.sendReq({token: TOKEN})\n}\n\n// Events\n$AEV(window, 'load', loadUsers)\n\n// Effects\n$fx.setWidth($('fluffy_4'), {from: 150, to: 400})\n\n// Array helpers\n$arrayFlatten([[1, 2, [3, 4]], 5]) == [1, 2, 3, 4, 5]\n\n// DOM abstraction\n$add($body(),\n     DIV({c: 'my_class', s:'padding-top: 10px'}, \"Hello\"))\n\n// Element store\nElementStore.set(elm, \"meaning of life\", {42: 42})\n```\n\n\n### Inspirations\n\nA lot of ideas from ICE comes from [MochiKit](http://mochikit.com/). The effects library is inspired by [mootools](http://mootools.net/).\n\n\n### Not polluting the global namespace\n\nBy default ICE exports its public functions to the global name space (window). \nIf you want to disable this set __window.ICE_EXPORT_TO_SCOPE = false__ before sourcing the library.\nThen use the __ICE.__ prefix to access the API.\n\n\n## General accessors functions\n\n\n* $isWebkit -- Returns true if the browser is webkit\n* $isIe -- Returns true if the browser is Internet Explorer\n* $isIe8 -- Returns true if the browser is Internet Explorer v8\n* $isSafari -- Returns true if the browser is Safari\n* $isOpera -- Returns true if the browser is Opera\n* $isMozilla -- Returns true if the browser is Mozilla\n* $isMac -- Returns true if the browser is a Mac\n* $isChrome -- Returns true if the browser is a Chrome\n* $queryArgument(var_name) -- Returns the value of __var_name__ from the URL\n\n\n## Array functions\n\n\n* $arrayCreate(val) -- Returns __val__ if it's already an array, otherwise [__val__] is returned. Shortcut $A\n* $arrayCompare(arr_a, arr_b) -- Returns true if __arr_a__ and __arr_b__ are equal\n* $arrayRemove(array, elm [,eval_fn]) -- Removes __elm__ from __array__\n* $arrayUpdate(array, old_elm, new_elm) -- Updates __old_elm__ to __new_elm__ inside array\n* $arrayCopy(array) -- Returns a copy of __array__\n* $arrayDiff(arr1, arr2) -- Returns the diff between __arr1__ and __arr2__\n* $arrayUnion(arr1, arr2) -- Returns the union between __arr1__ and __arr2__\n* $arrayForce(args) -- Returns a true array. This functions is useful to force arguments to act as an array instead of an object. Shortcut $AF\n* $arrayJoin(delim, array) -- Returns the elements of __array__ as string, separated by the specified delimiter __delim__\n* $isIn(elm, array) -- Returns true if __elm__ is inside __array__\n* $index(elm, array [,eval_fn]) -- Returns the index of __elm__ inside __array__. -1 is returned if the __elm__ isn't found\n* $first(array) -- Returns the first element of __array__\n* $last(array) -- Returns the last element of __array__\n* $random(array) -- Returns an random element of __array__\n* $arrayFlatten(array) -- Returns a flattened __array__\n* $update(obj1, obj2) -- Update __obj1__ with properties from __obj2__\n\n```javascript\n$isIn(\"cow\", [1, 2, \"cow\"]) == true\n$getIndex(\"cow\", [1, 2, \"cow\"]) == 2\n$update({a: 1, b: 2}, {c: 3}) == {a: 1, b: 2, c: 3}\n$arrayFlatten([[1, 2, [3, 4]], 5]) == [1, 2, 3, 4, 5]\n```\n\n\n## Functional programming\n\n* $map(array, fn, [start_index, end_index]) -- Executes __fn__ on all elements of __array__. Signature is fn(element, index)\n* $rmap(array, fn, [start_index, end_index]) -- Like $map, but in reverse\n* $filter(array, fn, [start_index, end_index]) -- Executes __fn__ on all elements of __array__ and returns all the elements of list where __fn(elm)__ equals true\n* $partial(fn) -- Return a partially applied function. Shortcut $p\n\n```javascript\ndiv_with_2 = $filter([1, 5, 8, 4], function(n) {\n     return (n % 2 == 0)\n})\ndiv_with_2 == [8, 4]\n\nadder = function(a, b) {\n    return a + b\n}\nadd_one = $partial(adder, 1)\nadd_one(41) == 42\n```\n\n\n## DOM accessors\n\n* $(id) -- Returns the DOM element with the __id__\n* $$(selector, [in_children]) -- Returns a list of DOM elements that match the CSS __selector__\n* $nodeName(elm) -- Returns the node name of __elm__\n* $parent(elm, tag_name, [class_name, stop_elm]) -- Look on __elm__ parents and return the first match. The search stops when __stop_elm__ is reached. Shortcut $gp\n* $child(elm, tag_name, [class_name, stop_elm]) -- Look on __elm__ children and return the first match. Shortcut $gc\n* $prevSibling(elm, tag_name, class_name) -- Look on __elm__ previous siblings and return the first match\n* $nextSibling(elm, tag_name, class_name) -- Look on __elm__ next siblings and return the first match\n* $body() -- Returns the body DOM element\n* $head() -- Returns the head DOM element\n* $form(form, name) -- Returns a form element with the specified __name__. Shortcut $f\n* $selectValue(select) -- Returns value of __select__\n* $all(tag_name, class_name, [parent, first_match]) -- [Deprecated, use $$ isntead]. Returns a list of DOM elements. To ignore the tag_name or class_name set them to null. The whole document is searched if parent isn't set\n\n```javascript\n// Returns one element with id google_login\n$('google_login') \n\n// Returns all of div elements\n$$('div') \n\n// Returns div elements with .user class inside #google_list\n$$('div.user', $('google_list')) \n\n// Returns the div.facebook_login that's the first sibling of #google_list\n$nextSibling($('google_list'), 'div', 'facebook_login')\n\n// Returns the first parent of #google_list that matches div.holder\n$parent($('google_list'), 'div', 'holder') \n\n// Returns the first child of #google_list that matches li.user\n$child($('google_list'), 'li', 'user') \n\n// Deprecated (use $$): Returns div tags with user class inside #google_list\n$all('div', 'user', $('google_list')) \n```\n\n\n## DOM mutators\n\n* $documentInsert(elm) -- Write element to the document (using document.write)\n* $toDOM(html, [first_child]) -- Transform __html__ to DOM. Returns first child if __first_child__ is true \n* $add(elm, elm1, ..., elmN) -- Add __elm1,...,elmN__ to __elm__\n* $addToTop(elm, elm1, ..., elmN) -- Add __elm1,...,elmN__ to the top of __elm__. Shortcut $ATT\n* $replace(elm, elm1, ..., elmN) -- Replace children of __elm__ with __elm1,...,elmN__\n* $addAfter(elm, reference_elm) -- Add __elm__ after __reference_elm__\n* $addBefore(elm, reference_elm) -- Add __elm__ before __reference_elm__\n* $clean(elm) -- Clean data, events, etc. attached to __elm__\n* $swap(dest, src) -- Swap __dest__ with __src__\n* $remove(elm1, ..., elmN) -- Remove __elm1,...,elmN__\n* $create(tag_name, attrs) -- Create a new DOM element with __tag_name__. __attrs__ should be an object or array\n* $setHTML(elm1, ..., elmN, html) -- Set the innerHTML of __elm1,...,elmN__ to html\n\nDOM shortcuts. These elements have shortcuts:\n* UL, LI, TD, TR, TH,\n* TBODY, TABLE, INPUT, SPAN, B,\n* A, DIV, IMG, BUTTON, H1,\n* H2, H3, H4, H5, H6, BR, TEXTAREA, FORM,\n* P, SELECT, OPTION, OPTGROUP, IFRAME, SCRIPT,\n* CENTER, DL, DT, DD, SMALL,\n* PRE, I, LABEL, THEAD, HR\n\n```javascript\n// Using $create\n$create(\"p\", [{id: \"my_p\", style: \"color: red\"}, \"Hello world\"])\n\n// Using the shortcuts\n$add($body(),\n     DIV({c: 'my_class', s:'padding-top: 10px'}, \"Hello\"))\n\n// Inserting a DIV elemetn to the body\n$insertAfter(DIV(\"Hello\"), $body())\n```\n\n\n## CSS - visibility\n\n* $setVisibility(elm1, ..., elmN, visibility) -- Update visibility of __elm1,...,elmN__\n* $setOpacity(elm1, ..., elmN, value) -- Update opacity to __value__ of __elm1,...,elmN__\n* $show(elm1, ..., elmN) -- Show __elm1,...,elmN__\n* $hide(elm1, ..., elmN) -- Hide __elm1,...,elmN__\n* $isHidden(elm) -- Returns true if __elm__ is hidden. Otherwise false\n* $isShown(elm) -- Returns true if __elm__ is shown. Otherwise false\n\n```javascript\n$show($$('div.user'))\n$isHidden($('google_login')) == true\n$setVisibility($$('div.user'), false)\n$setOpacity($$('div.user'), 0.5)\n```\n\n## CSS - style updates\n\n* $setStyle(elm1, ..., elmN, obj) -- Update elm.style with __obj__ of __elm1,...,elmN__\n* $getStyle(elm, property) -- Return the computed style of __elm__\n* $setWidth(elm1, ..., elmN, width) -- Set width of __elm1,...,elmN__\n* $setHeight(elm1, ..., elmN, height) -- Set height of __elm1,...,elmN__\n* $setLeft(elm1, ..., elmN, left) -- Set left of __elm1,...,elmN__\n* $setRight(elm1, ..., elmN, right) -- Set right of __elm1,...,elmN__\n* $setTop(elm1, ..., elmN, top) -- Set top of __elm1,...,elmN__\n* $setBottom(elm1, ..., elmN, bottom) -- Set bottom of __elm1,...,elmN__\n\n```javascript\n$setStyle($$('div.user'), {top: 50, left: 40})\n$setTop($$('div.user'), 100)\n```\n\n## CSS - classes \n\n* $setClass(elm1, ..., elmN, class) -- Set class of __elm1,...,elmN__\n* $addClass(elm1, ..., elmN, class) -- Add class to __elm1,...,elmN__\n* $removeClass(elm1, ..., elmN, class) -- Remove class class __elm1,...,elmN__\n* $replaceClass(elm1, ..., elmN, classOld, classNew) -- Replace classOld with classNew in __elm1,...,elmN__\n* $hasClass(elm, class) -- Returns true if __elm__ has __class__\n\n```javascript\n$setClass($$('div.user', $('google_login')), 'user_deleted')\n$addClass($('user_a'), $('user_b'), 'user_loading')\n```\n\n\n## Position and size\n\n* $mousePos(event) -- Returns the mouse position of __event__ as {x: ..., y: ...}\n* $scrollTop(elm) -- Scrolls __elm__ to the top\n* $position(elm) -- Returns the absolute position of __elm__ as {x: ..., y: ...}\n* $docSize([doc]) -- Returns the document size of __doc__ as {w: ..., h: ...}\n* $winSize([doc]) -- Returns the window size as {w: ..., h: ...} by inspecting __doc__\n* $isOverlapping(elm1, elm2) -- Returns true if elm1 is overlapping elm2\n\n```javascript\n$position($('my_elm')) == {x: 100, y: 200}\n$isOverlapping($('elm1'), $('elm2')) == true\n```\n\n\n## Events\n\n* $eventElm(event) -- Returns the element that's tied to __event__\n* $addListener(elms, types, handler, [listen_once]) -- Add a __handler__ that handles __types__. Shortcut $AEV\n* $removeListener(elms, types, handler, [listen_once]) -- Remove __handler__ from __elms__ that handles __types__. Shortcut $REV\n* $removeAllListeners(elms, type) -- Remove all handlers that handle __type__\n\n```javascript\n$AEV($$('div.user'), 'click', function(ev) {\n    $preventDefault(ev)\n    var elm = $eventElm(ev)\n    // ...\n})\n\n$AEV([$('input_1'), $('input_2')], 'keypress', function(ev) {\n    alert(ev.key)\n    alert(ev.ctrl)\n    alert(ev.meta)\n})\n\n$AEV($('google_btn'), 'click' $b(googleBtnClick, GoogleUser) {\n    // this points to GoogleUser\n});\n```\n\n### Preventing default behaviour \n\n* $preventDefault(event) -- Prevent the default behavior of an event\n* $stopPropagation(event) -- Stop propagation of an event\n\n## Binding functions\n\n* $bind(fn, scope, [extra_args]) -- Bind function __fn__ to __scope__ and return it. __extra_args__ is an array of extra parameters that should be sent to __fn__. Shortcut $b\n* $bindMethods(object) -- Force binding all of methods of __object__ to itself. Useful to resolve __this__\n\n\n\n## Requests\n\n* $request(url, method) -- Perform a request to __url__ and return it in a deferred object. __method__ can be get or post\n* $requestJSON(url, method) -- Like $request, but parse the result as JSON\n* $httpReq() -- Returns a new XMLHTTPRequest\n* $serialize(obj) -- Serialize __obj__ as JSON\n* $eval(txt) -- Evaluate __txt__ as JavaScript or JSON (if possible) and return the result\n* $evalScript(html) -- Evaluate script tags inside __txt__\n* $encode(data) -- Return the query argument representation of __data__\n\n```javascript\nd = $request('/feeds/json/amix')\nd.addCallback(function(res_txt, req) { alert(res_txt) })\nd.addErrback(function(res_txt, req) { alert('Error encountered: ' + res_txt) })\nd.sendReq({val: 1})\n\n$serialize({'a': 1, 'b': 2}) == '{\"a\":1,\"b\":2}'\n$eval('{\"a\":1,\"b\":2}') == {'a': 1, 'b': 2}\n\n$encode({name: 'peter', 'age': 29}) == \"name=peter\u0026age=29\"\n```\n\n### Requests (deferred object)\n\nA deferred gives the option to chain functions. ICE borrowed this idea from [MochiKit](http://mochi.github.io/mochikit/) that borrowed it from [Twisted](https://twistedmatrix.com/trac/). ICE implementation is much more simple and limited than MochiKit's or Twisted's.\n\nWhen you call $request or $requestJSON you get a deferred object. This object has following methods:\n\n* addCallback(fn): Add the function fn to the end of the callback sequence\n* addErrback(fn): Add the function fn to the end of the errorback sequence\n* addCallbacks(callback, errback)\n* sendReq(data): Send the actual request. __data__ should be a JSON object\n\n\n\n## Class abstraction\n\nICE features a simple way to do OOP in JavaScript. A simple example that demonstrates all of the functionality:\n\n```javascript\nPerson = new Class({\n    init: function(name) {\n        this.name = name\n        Person.count++\n    },\n\n    getName: function() {\n        return this.name\n    }\n})\n\n// Static field\nPerson.count = 0\n\nUniversityPerson = Person.extend({\n\n    init: function(name, school) {\n        this.parent(name)\n        this.school = school\n    },\n\n    getSchool: function() {\n        return this.school\n    }\n})\n```\n\n\n## Effects - $fx\n\nYou can use $fx to create some dazzling effects.\n\n* $fx.highlight(elm, opts) -- Yellow highlight the element\n* $fx.fadeIn(elm, opts) -- Fade in the element\n* $fx.fadeOut(elm, opts) -- Fade out the element\n* $fx.setWidth(elm, opts) -- Animate resize of width\n* $fx.setHeight(elm, opts) -- Animate resize of height\n* $fx.Style(elm, opts) -- Animates an arbitrary effect\n* $fx.Styles(elm, opts) -- Animates an arbitrary effects\n\n```javascript\n$fx.highlight($('fluffy_1'), {duration: 1000})\n$fx.setWidth($('fluffy_4'), {from: 150, to: 400})\n\nnew $fx.Style($('fluffy_6'), 'width').custom(50, 300)\n\nnew $fx.Styles($('fluffy_7')).custom(\n   {'height': [50, 100], 'width': [150, 300]}\n)\n```\n\n\n## Drag and drop - $dnd\n\n$dnd makes it possible to support drag and drop. It provides a bare-bone where browser issues are solved. There is no drop-zones and no sortable lists, but you can implement these things using a few lines code.\n\nLook inside the examples directory for some ideas of how $dnd works.\n\n* $dnd.dragAble(element, opts) -- Make element drag able. The element's style.position should be absolute\n* $dnd.removeDragAble(element) -- Remove the drag ability from element\n* $dnd.current_root -- When dragging begins this object holds the element that is moved\n* $dnd.current_handler -- When dragging begins this object holds the element that drags \n\nThe __opts__ to $dnd.dragAble can be following. All of them are optional.\n* move_x -- Enable horizontal move. Default true\n* move_y -- Enable vertical move. Default true\n* scroll_on_overflow -- Scroll the page on overflow. Default true\n* on_start -- A callback that is triggered when the drag is started. Signature is on_start()\n* on_drag -- A callback that is triggered when a dragable is dragged. Signature is on_drag(new_x, new_y)\n* on_end -- A callback that is triggered when the drag is stopped. Signature is on_start()\n* move_filter: This function can control the x and y coordinates. Signature is move_filter(x, y) -\u003e [x, y]\n\n```javascript\nvar drop_red = $('drop_red')\nvar drop_blue = $('drop_blue')\n\nvar onDrag = function() {\n    var root = $dnd.current_root\n\n    if($isOverlapping(root, drop_red))\n        $addClass(root, 'color_red')\n    else if($isOverlapping(root, drop_blue))\n        $addClass(root, 'color_blue')\n    else {\n        $removeClass(root, 'color_blue')\n        $removeClass(root, 'color_red')\n    }\n}\n\n$dnd.dragAble($('draggy'), {\n    handler: $('draggy_handler'),\n    on_drag: onDrag\n})\n```\n\n\n## Element store\n\n[jQuery.data](http://api.jquery.com/jQuery.data/#jQuery.data1) allows you to attach data of any type to DOM elements in a way that is safe from circular references and therefore from memory leaks. ICE a standalone jQuery.data library called ElementStore - - which is also a standalone library [github.com/Doist/ElementStore](https://github.com/Doist/ElementStore).\n\n* ElementStore.set(elm, key, value)\n* ElementStore.get(elm, key)\n* ElementStore.remove(elm, key) -- Remove one key\n* ElementStore.remove(elm) -- Removes all keys\n\n```javascript\nElementStore.set(elm, \"meaning of life\", {42: 42})\nElementStore.get(elm, \"meaning of life\")\nElementStore.remove(elm, \"meaning of life\")\nElementStore.remove(elm)\n```\n\n\n## Misc\n* $keys(object) -- Returns the keys of __object__\n* $values(object) -- Returns the values of __object__\n* $urlencode(str) -- Returns URL encoding of __str__\n* $urldecode(str) -- Returns URL decoding of __str__\n* $defined(obj) -- Returns true if __obj__ is defined (not null or undefined)\n* $isArray(obj) -- Returns true if __obj__ is an array\n* $isString(obj) -- Returns true if __obj__ is a string\n* $isNumber(obj) -- Returns true if __obj__ is a number\n* $isObject(obj) -- Returns true if __obj__ is a object\n* $isFunction(obj) -- Returns true if __obj__ is a function\n* $isBoolean(obj) -- Returns true if __obj__ is a boolean\n* $isDict(obj) -- Returns true if __obj__ is a dictionary (e.g. {})\n* $log(obj) -- Write __obj__ to the log\n* $strip(str) -- Stripe prefix and suffix whitespace from __str__\n* $trim(str, limit, [delim]) -- Trim __str__ with __limit__ length and suffix it with __delim__ if needed. __delim__ is __...__ by default\n* $preload(img_src1, ..., img_srcN) -- Preload images __img_src1, ..., img_srcN__\n\n```javascript\n$keys({a: 1, b: 2, c: 3}) == [\"a\", \"b\", \"c\"]\n$values({a: 1, b: 2, c: 3}) == [1, 2, 3]\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdoist%2Fice","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdoist%2Fice","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdoist%2Fice/lists"}