bindify

# Bindify-JS
git clone http://git.code.weiherhei.de/bindify.git
Log | Files | Refs

commit 90f46db39579f1d8c956a00096d2778bf45054bf
parent cdade069cdd051ae405d5f411518a6ffb83fb827
Author: Jan Dankert <jan.dankert@hansemerkur.de>
Date:   Tue, 28 Jan 2020 17:10:19 +0100

The first running implementation.

Diffstat:
README.md | 2+-
bindify.js | 135++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
bindify.min.js | 18+++++++++++++++++-
3 files changed, 152 insertions(+), 3 deletions(-)

diff --git a/README.md b/README.md @@ -4,7 +4,7 @@ This is a lightweight javascript 2-way-data-binding framework, implemented as a ## Advantages -- Really lightweight +- Really lightweight, ~ 1kB (minified and gzipped) - does not need any [CSP](https://en.wikipedia.org/wiki/Content_Security_Policy) permissions. - 2-way-binding diff --git a/bindify.js b/bindify.js @@ -1,2 +1,135 @@ -/*! GPLv3 */ +/*! GPL */ /* bindify JQuery databinding plugin*/ +(function ( $ ) { + + $.fn.bindify = function( data={},options={} ) { + + let settings = $.extend({ + prefix: 'binding', + updateModel: true, + updateDOM: true, + updateCallback: $.Callbacks(), + debug: false, + updateEvent: 'input', + onUpdate: function(data) {}, + }, options ); + + let el = this; + + let updateDOM = function() { + + setTimeout( function() {bind(el,data)} , 0 ); + } + + settings.updateCallback.add( updateDOM ); + + let prefix = settings.prefix + '-'; + + // Enable writing back data from the DOM to the model. + if ( settings.updateModel) + $(el).find('[data-'+prefix+'value]').each( function() { + $(this).off(settings.updateEvent); + $(this).on(settings.updateEvent, function() { + + if ( settings.debug ) + console.log("Input event fired: "+this.value); + + assign(data,$(this).data(prefix+'value'),this.value); + settings.onUpdate(data); + settings.updateCallback.fire(); + } ); + }); + + + + let assign = function(obj, prop, value) { + if (typeof prop === "string") + prop = prop.split("."); + + if (prop.length > 1) { + var e = prop.shift(); + assign(obj[e] = + Object.prototype.toString.call(obj[e]) === "[object Object]" + ? obj[e] + : {}, + prop, + value); + } else + obj[prop[0]] = value; + } + + let getData = function( key,data ) { + function index(obj,i) { + return obj[i] + } + return key.split('.').reduce(index, data); + } + + // Lets do the data bind to a DOM element. + // This function is called recursively for all DOM children. + let bind = function( element,data) { + + let dataValue = element.data(prefix+'value'); + if ( dataValue ) { + element.val( getData( dataValue, data ) ); + // Change listener for writing back the input to the model + } + + let dataText = element.data(prefix+'text'); + if ( dataText ) + element.text( getData( dataText, data ) ); + + let dataAttributes = element.data(prefix+'attributes'); + if ( dataAttributes ) { + // JQuery is parsing the JSON automatically + Object.keys(dataAttributes).forEach(function (key) { + element.attr(key, getData(dataAttributes[key],data)) + },this); + } + + let dataList = element.data(prefix+'list'); + if ( dataList ) { + let eachData = getData( dataList, data ); + + let children = $(element).children(); + let firstChild = children.first(); + let isLength = children.length; + let shouldLength = eachData.length; + if ( isLength > 0 ) + { + // Add children to force the correct children count + for( let i=isLength+1; i<=shouldLength; i++ ) + firstChild.clone().appendTo( element ); + // Remove children to force the correct children count + for( let i=shouldLength+1; i<=isLength; i++ ) + element.children().last().remove(); + + let key = dataList; + let dataVar = element.data(prefix+'var'); + if ( dataVar ) + key = dataVar; + + for( let i=0; i<eachData.length; i++) { + let childData = {}; + childData[key] = eachData[i]; + let computedDataForChild = Object.assign({},data,childData); + bind( children.eq(i),computedDataForChild ); + }; + + } + } + else{ + $(element).children().each( function() { + bind($(this),data ); + }); + } + }; + + // Initial Binding + settings.updateCallback.fire(); + + // JQuery should stay chainable. + return this; + }; + +}( jQuery )); diff --git a/bindify.min.js b/bindify.min.js @@ -1 +1,16 @@ -/*! GPLv3 */ +(function($){$.fn.bindify=function(data={},options={}){let settings=$.extend({prefix:'binding',updateModel:!0,updateDOM:!0,updateCallback:$.Callbacks(),debug:!1,updateEvent:'input',onUpdate:function(data){},},options);let el=this;let updateDOM=function(){setTimeout(function(){bind(el,data)},0)} + settings.updateCallback.add(updateDOM);let prefix=settings.prefix+'-';if(settings.updateModel) + $(el).find('[data-'+prefix+'value]').each(function(){$(this).off(settings.updateEvent);$(this).on(settings.updateEvent,function(){if(settings.debug) + console.log("Input event fired: "+this.value);assign(data,$(this).data(prefix+'value'),this.value);settings.onUpdate(data);settings.updateCallback.fire()})});let assign=function(obj,prop,value){if(typeof prop==="string") + prop=prop.split(".");if(prop.length>1){var e=prop.shift();assign(obj[e]=Object.prototype.toString.call(obj[e])==="[object Object]"?obj[e]:{},prop,value)}else obj[prop[0]]=value} + let getData=function(key,data){function index(obj,i){return obj[i]} + return key.split('.').reduce(index,data)} + let bind=function(element,data){let dataValue=element.data(prefix+'value');if(dataValue){element.val(getData(dataValue,data))} + let dataText=element.data(prefix+'text');if(dataText) + element.text(getData(dataText,data));let dataAttributes=element.data(prefix+'attributes');if(dataAttributes){Object.keys(dataAttributes).forEach(function(key){element.attr(key,getData(dataAttributes[key],data))},this)} + let dataList=element.data(prefix+'list');if(dataList){let eachData=getData(dataList,data);let children=$(element).children();let firstChild=children.first();let isLength=children.length;let shouldLength=eachData.length;if(isLength>0) + {for(let i=isLength+1;i<=shouldLength;i++) + firstChild.clone().appendTo(element);for(let i=shouldLength+1;i<=isLength;i++) + element.children().last().remove();let key=dataList;let dataVar=element.data(prefix+'var');if(dataVar) + key=dataVar;for(let i=0;i<eachData.length;i++){let childData={};childData[key]=eachData[i];let computedDataForChild=Object.assign({},data,childData);bind(children.eq(i),computedDataForChild)}}} + else{$(element).children().each(function(){bind($(this),data)})}};settings.updateCallback.fire();return this}}(jQuery))+ \ No newline at end of file