Comparing version 1.0.0-beta3 to 1.0.0-beta4
@@ -981,3 +981,3 @@ /** | ||
source.on('change', handleFilterSourceChanged2.bind(this)), | ||
this.matcherProperty.subscribe(updateFilter, this), | ||
this.matcherProperty.subscribe(updateFilter, this) | ||
]; | ||
@@ -984,0 +984,0 @@ this._data = filter(this, source); |
@@ -47,2 +47,4 @@ /** | ||
Class(DependencyProperty).extends(Property).def({ | ||
get writable() { return this.set !== null; }, | ||
_bindings: null, | ||
@@ -49,0 +51,0 @@ /** |
@@ -219,3 +219,3 @@ /// @internal | ||
document.body.appendChild(clonedNode); | ||
var result = DOM.measure(clonedNode); | ||
var result = DOM.measure(clonedNode, false); | ||
document.body.removeChild(clonedNode); | ||
@@ -222,0 +222,0 @@ return result; |
@@ -71,3 +71,3 @@ /** | ||
} | ||
this.emit('newListener', event, listener); | ||
if(this[$listeners].newListener) this.emit('newListener', event, listener); | ||
var subscription = new Subscription(this, event, listener); | ||
@@ -111,3 +111,3 @@ listeners[listeners.length] = subscription; | ||
listener.dispose(); | ||
this.emit('removeListener', event, listener); | ||
if(this[$listeners].removeListener) this.emit('removeListener', event, listener); | ||
} | ||
@@ -134,3 +134,3 @@ } | ||
} | ||
this.emit('removeListener', event, listener); | ||
if(this[$listeners].removeListener) this.emit('removeListener', event, listener); | ||
return true; | ||
@@ -172,8 +172,22 @@ } | ||
listeners = listeners.slice(); | ||
args = _.asArray(arguments).slice(1); | ||
var params; | ||
switch(arguments.length) { | ||
case 1: | ||
params = []; | ||
break; | ||
case 2: | ||
params = [args]; | ||
break; | ||
case 3: | ||
params = [args, arguments[2]]; | ||
break; | ||
default: | ||
params = arguments.length === 2 ? [args] : _.asArray(arguments).slice(1); | ||
break; | ||
} | ||
for(var i = 0, len = listeners.length; i < len; ++i) { | ||
listeners[i].notify(args); | ||
listeners[i].notify(params); | ||
} | ||
} | ||
if(event !== 'all') { | ||
if(event !== 'all' && this[$listeners].all) { | ||
this.emit.apply(this, ['all'].concat(_.asArray(arguments))); | ||
@@ -180,0 +194,0 @@ } |
@@ -37,2 +37,49 @@ /** | ||
/** | ||
* Creates an Observable whose value is resolved asynchronously. | ||
* The `callback` will receive the original observable and is expected to return | ||
* a Promise. Once that Promise is resolved, the value of the new observable will | ||
* be changed to the value that the Promise was resolved too. | ||
* | ||
* @example | ||
* // this example demonstrates how to limit evaluation to the animation frame. | ||
* Observable.computed(function() { | ||
* return 2 * 2; // slow calculation | ||
* }).async(function(resultObservable) { | ||
* var defer = new Deferred(); | ||
* Dispatcher.requestAnimationFrame(function() { | ||
* defer.fulfill(resultObservable.get()); | ||
* }); | ||
* return defer.promise; | ||
* }).subscribe(function(event) { | ||
* // do something with event.value | ||
* }); | ||
* | ||
* @memberof module:jidejs/base/Observable.prototype | ||
* @param {Function} callback | ||
* @returns {Observable} | ||
*/ | ||
async: function(arg, callback) { | ||
var result = new Observable(null), | ||
promise, | ||
self = arguments.length === 1 ? this : arg, | ||
successHandler = function(value) { | ||
promise = null; | ||
result.set(value); | ||
}, | ||
failureHandler = function(reason) { | ||
promise = null; | ||
result.set(reason); | ||
}; | ||
callback || (callback = arg); | ||
self.subscribe(function() { | ||
if(!promise) { | ||
promise = callback(self).then(successHandler, failureHandler); | ||
} | ||
}); | ||
promise = callback(self).then(successHandler, failureHandler); | ||
return result; | ||
}, | ||
/** | ||
* This type of binding can be used to create a property whose value changes when the bound property | ||
@@ -517,4 +564,14 @@ * takes a truthy or falsy value. | ||
*/ | ||
notify: function() { | ||
this.emit.apply(this, ['change'].concat(_.asArray(arguments))); | ||
notify: function(event) { | ||
switch(arguments.length) { | ||
case 0: | ||
this.emit('change'); | ||
break; | ||
case 1: | ||
this.emit('change', event); | ||
break; | ||
default: | ||
this.emit.apply(this, ['change'].concat(_.asArray(arguments))); | ||
break; | ||
} | ||
}, | ||
@@ -593,3 +650,5 @@ | ||
return new Binding(this, target, Binding.ONE_WAY, converter); | ||
} | ||
}, | ||
get writable() { return true; } | ||
}); | ||
@@ -613,2 +672,4 @@ | ||
Class(ComputedObservable).extends(Observable).def({ | ||
get writable() { return this.writeValue !== null; }, | ||
set: function(value) { | ||
@@ -628,8 +689,18 @@ if(this.writeValue) { | ||
var deps = DependencyTracker.end(this); | ||
this._bindings.forEach(function(binding) { binding.dispose(); }); | ||
this._bindings = []; | ||
var invalidate = this.invalidate.bind(this); | ||
for(var i = 0, len = deps.length; i < len; ++i) { | ||
this._bindings.push(deps[i].subscribe(invalidate)); | ||
} | ||
// check if this._bindings and deps are the same | ||
var isDirty = deps.length !== this._bindings.length; | ||
for(var bindings = this._bindings, i = 0, len = bindings.length; !isDirty && i < len; i++) { | ||
if(bindings[i] !== deps[i]) { | ||
isDirty = true; | ||
} | ||
} | ||
if(isDirty) { | ||
this._bindings.forEach(function(binding) { binding.dispose(); }); | ||
this._bindings = []; | ||
var invalidate = this.invalidate.bind(this); | ||
for(var i = 0, len = deps.length; i < len; ++i) { | ||
this._bindings.push(deps[i].subscribe(invalidate)); | ||
} | ||
} | ||
this.invalid = false; | ||
@@ -636,0 +707,0 @@ } else { |
@@ -36,2 +36,4 @@ /** | ||
Class(ObservableProperty).extends(Property).def({ | ||
get writable() { return true; }, | ||
/** | ||
@@ -38,0 +40,0 @@ * Returns the current value of the property. |
@@ -75,4 +75,14 @@ /** | ||
notify: function() { | ||
this._context.emit.apply(this._context, ['change:'+this._name].concat(_.asArray(arguments))); | ||
notify: function(event) { | ||
switch(arguments.length) { | ||
case 0: | ||
this._context.emit('change:'+this._name); | ||
break; | ||
case 1: | ||
this._context.emit('change:'+this._name, event); | ||
break; | ||
default: | ||
this._context.emit.apply(this._context, ['change:'+this._name].concat(_.asArray(arguments))); | ||
break; | ||
} | ||
}, | ||
@@ -79,0 +89,0 @@ |
{ | ||
"name": "jide", | ||
"version": "1.0.0-beta3", | ||
"version": "1.0.0-beta4", | ||
"author": "Patrick Gotthardt, <patrick@jidesoft.com>", | ||
@@ -31,22 +31,52 @@ "description": "jide.js is a free UI toolkit for modern web applications based on data binding and separation of concerns.", | ||
"files": [ | ||
"base", "ui", "style", "package.json", "LICENSE", "README.md" | ||
"base", | ||
"ui", | ||
"style", | ||
"package.json", | ||
"LICENSE", | ||
"README.md" | ||
], | ||
"devDependencies": { | ||
"wintersmith-less": "~0.2.1", | ||
"wintersmith-nunjucks": "~0.2.1", | ||
"cheerio": "~0.12", | ||
"wintersmith": "latest", | ||
"wintersmith-less": "octavore/wintersmith-less#coffeescript-1.7-compat", | ||
"wintersmith-nunjucks": "latest", | ||
"cheerio": "latest", | ||
"express": "~3.4", | ||
"jsdoc": "~3.2.2", | ||
"less-middleware": "~0.1.14", | ||
"intern": "~1.3.2", | ||
"gulp-uglify": "~0.1.0", | ||
"gulp": "~3.4.0", | ||
"gulp-header": "~1.0.2", | ||
"gulp-less": "~1.1.10", | ||
"gulp-zip": "~0.1.2", | ||
"gulp-replace": "~0.2.0", | ||
"gulp-footer": "~1.0.3", | ||
"gulp-exec": "~1.0.4", | ||
"wintersmith": "~2.0.10" | ||
"gulp": "latest", | ||
"gulp-uglify": "latest", | ||
"gulp-header": "latest", | ||
"gulp-less": "latest", | ||
"gulp-zip": "latest", | ||
"gulp-replace": "latest", | ||
"gulp-footer": "latest", | ||
"gulp-exec": "latest", | ||
"gulp-minify-css": "latest", | ||
"gulp-requirejs": "pago/gulp-requirejs#patch-1", | ||
"gulp-clean": "latest", | ||
"requirejs": "~2.1.11", | ||
"karma-script-launcher": "~0.1.0", | ||
"karma-chrome-launcher": "~0.1.2", | ||
"karma-firefox-launcher": "~0.1.3", | ||
"karma-html2js-preprocessor": "~0.1.0", | ||
"karma-jasmine": "~0.1.5", | ||
"karma-requirejs": "~0.2.1", | ||
"karma-coffee-preprocessor": "~0.1.2", | ||
"karma-phantomjs-launcher": "~0.1.2", | ||
"karma": "~0.10.9", | ||
"karma-ie-launcher": "~0.1.1", | ||
"karma-benchmark": "~0.3.1", | ||
"karma-spec-reporter": "0.0.9", | ||
"mocha": "~1.17.1", | ||
"karma-mocha": "~0.1.1", | ||
"karma-chai": "0.0.2", | ||
"gulp-rename": "~1.1.0", | ||
"gulp-changed": "~0.2.0", | ||
"event-stream": "~3.1.0", | ||
"gulp-util": "~2.2.14", | ||
"wintersmith-livereload": "~0.1.1", | ||
"gulp-csso": "~0.2.3", | ||
"gulp-imagemin": "~0.1.5" | ||
} | ||
} |
415
ui/bind.js
@@ -5,8 +5,14 @@ /// @internal | ||
define([ | ||
'./../base/Observable', './../base/DOM', './../base/Util', | ||
'./util/ClassList', './util/js-object-literal-parse', './Component' | ||
], function(Observable, DOM, _, ClassList, literalParse, Component) { | ||
'./../base/Observable', './../base/DOM', './../base/Util', './../base/Dispatcher', | ||
'./util/ClassList', './util/js-object-literal-parse', './Component', | ||
'./bind/content', './bind/foreach', './bind/style' | ||
], function( | ||
Observable, DOM, _, Dispatcher, ClassList, literalParse, Component, | ||
contentBindings, foreachBindings, styleBindings | ||
) { | ||
"use strict"; | ||
var _require; | ||
foreachBindings = foreachBindings(bind); | ||
var _require, toString = Object.prototype.toString; | ||
if(window.define && window.define.amd) { | ||
@@ -30,65 +36,91 @@ _require = function(dependency, callback) { | ||
function upgradeElement(element, descriptor, context, component) { | ||
var controlId = descriptor.is(), | ||
controlInstance = component || null, | ||
disposable = { | ||
controlsChildren: true, | ||
dispose: function() { | ||
controlInstance.dispose(); | ||
controlInstance = null; | ||
element = null; | ||
descriptor = null; | ||
context = null; | ||
} | ||
}; | ||
delete descriptor.is; | ||
_require(controlId, function(Control) { | ||
var names = Object.getOwnPropertyNames(descriptor) || [], | ||
config = {}; | ||
for(var i = 0, len = names.length; i < len; i++) { | ||
var name = names[i], | ||
value = name === 'on' ? descriptor[name]() : Observable.computed(descriptor[name]); | ||
config[name] = value; | ||
} | ||
if(!controlInstance) { | ||
config['element'] = element; | ||
controlInstance = new Control(config); | ||
} else { | ||
Component.applyConfiguration(controlInstance, config); | ||
} | ||
controlInstance.emit('ComponentReady', { | ||
source: element, | ||
component: controlInstance | ||
}); | ||
}); | ||
return disposable; | ||
} | ||
function updateBindings(element, context, isInit, updates, oldValues) { | ||
for(var i = 0, len = updates.length; i < len; i++) { | ||
var update = updates[i], | ||
name = update[0], | ||
value = update[1], | ||
oldValue = oldValues[name]; | ||
if(isInit || value !== oldValue) { | ||
if(bind.handlers.hasOwnProperty(name)) { | ||
if(isInit && bind.handlers[name].hasOwnProperty('init')) { | ||
bind.handlers[name].init(element, context); | ||
} | ||
bind.handlers[name].update(element, value, oldValue, context); | ||
oldValues[name] = value; | ||
} else { | ||
console.log('Trying to use undefined binding handler '+name+' on element', element); | ||
} | ||
} | ||
} | ||
} | ||
function bind(element, descriptor, context, component) { | ||
var oldValues = {}; | ||
var state = 0; // 0 -> init, 1 -> update | ||
var controlsChildren = false; | ||
var oldValues = {}, | ||
controlsChildren = false, | ||
updateTicking = false; | ||
if(descriptor.is) { | ||
var controlId = descriptor.is(), | ||
controlInstance = component || null, | ||
disposable = { | ||
controlsChildren: true, | ||
dispose: function() { | ||
controlInstance.dispose(); | ||
controlInstance = null; | ||
element = null; | ||
descriptor = null; | ||
context = null; | ||
} | ||
}; | ||
delete descriptor.is; | ||
_require(controlId, function(Control) { | ||
var names = Object.getOwnPropertyNames(descriptor) || [], | ||
config = {}; | ||
return upgradeElement(element, descriptor, context, component); | ||
} | ||
var binding = Observable.computed({ | ||
read: function() { | ||
var names = Object.getOwnPropertyNames(descriptor) || []; | ||
var result = []; | ||
for(var i = 0, len = names.length; i < len; i++) { | ||
var name = names[i], | ||
value = name === 'on' ? descriptor[name]() : Observable.computed(descriptor[name]); | ||
config[name] = value; | ||
value = descriptor[name](); | ||
if(value && toString.call(value) === '[object Object]' | ||
&& ('get' in value) && ('subscribe' in value)) { | ||
value = value.get(); | ||
} | ||
result[result.length] = [name, value]; | ||
} | ||
if(!controlInstance) { | ||
config['element'] = element; | ||
controlInstance = new Control(config); | ||
} else { | ||
Component.applyConfiguration(config); | ||
} | ||
controlInstance.emit('ComponentReady', { | ||
source: element, | ||
component: controlInstance | ||
return result; | ||
} | ||
}); | ||
binding.subscribe(function() { | ||
if(!updateTicking) { | ||
updateTicking = true; | ||
Dispatcher.requestAnimationFrame(function() { | ||
updateBindings(element, context, false, binding.get(), oldValues); | ||
updateTicking = false; | ||
}); | ||
}); | ||
return disposable; | ||
} | ||
var binding = Observable.computed({ | ||
lazy: false, | ||
read: function() { | ||
var names = Object.getOwnPropertyNames(descriptor) || []; | ||
for(var i = 0, len = names.length; i < len; i++) { | ||
var name = names[i], | ||
value = Observable.unwrap(descriptor[name]()), | ||
oldValue = oldValues[name]; | ||
if(state === 0 || value !== oldValue) { | ||
if(bind.handlers.hasOwnProperty(name)) { | ||
if(state === 0 && bind.handlers[name].hasOwnProperty('init')) { | ||
controlsChildren = bind.handlers[name].init(element, context) || controlsChildren; | ||
} | ||
bind.handlers[name].update(element, value, oldValue, context); | ||
oldValues[name] = value; | ||
} else { | ||
console.log('Trying to use undefined binding handler '+name+' on element', element); | ||
} | ||
} | ||
} | ||
state = 1; | ||
} | ||
}); | ||
binding.get(); // make it apply the bindings for the first time | ||
} | ||
}); | ||
updateBindings(element, context, true, binding.get(), oldValues); | ||
return { | ||
@@ -153,12 +185,2 @@ controlsChildren: controlsChildren, | ||
function pushContext(parentContext, data) { | ||
parentContext || (parentContext = defaultContext); | ||
var context = Object.create(data); | ||
context.$parentContext = parentContext; | ||
context.$parent = parentContext.$item; | ||
context.$item = data; | ||
context.$root = parentContext.$root; | ||
return context; | ||
} | ||
function createDisposable(disposables) { | ||
@@ -222,247 +244,12 @@ return { | ||
bind.handlers = { | ||
text: { | ||
update: function(element, value, oldValue, context) { | ||
if(value !== oldValue) { | ||
DOM.setTextContent(element, value || ''); | ||
} | ||
} | ||
}, | ||
text: contentBindings.text, | ||
html: contentBindings.html, | ||
content: contentBindings.content, | ||
html: { | ||
update: function(element, value, oldValue, context) { | ||
if(_.isString(value)) { | ||
element.innerHTML = value; | ||
} else { | ||
DOM.removeChildren(element); | ||
if(value) { | ||
DOM.appendChild(value); | ||
} | ||
} | ||
} | ||
}, | ||
style: styleBindings.style, | ||
css: styleBindings.css, | ||
attr: styleBindings.attr, | ||
css: { | ||
update: function(element, value, oldValue, context) { | ||
var component = DOM.hasData(element) && DOM.getData(element).component || null, | ||
target = component || (element.classList && element) || new ClassList(element), | ||
classes = Object.getOwnPropertyNames(value); | ||
classes.forEach(function(className) { | ||
if(value[className]) { | ||
target.classList.add(className); | ||
} else { | ||
target.classList.remove(className); | ||
} | ||
}); | ||
if(oldValue) { | ||
Object.getOwnPropertyNames(oldValue).forEach(function(className) { | ||
if(!value.hasOwnProperty(className)) { | ||
target.classList.remove(className); | ||
} | ||
}); | ||
} | ||
} | ||
}, | ||
foreach: foreachBindings.foreach, | ||
style: { | ||
update: function(element, value) { | ||
Object.getOwnPropertyNames(value).forEach(function(styleName) { | ||
element.style[styleName] = value[styleName] || ''; | ||
}); | ||
} | ||
}, | ||
content: { | ||
init: function(element, context) { | ||
if(element.createShadowRoot) { | ||
var contentClass = getBindData(element).contentClass = createRandomShadowContentClass(); | ||
// add content element at insertion point | ||
var content = document.createElement('content'); | ||
content.select = '.'+contentClass; | ||
element.appendChild(content); | ||
} | ||
}, | ||
update: function(element, value, oldValue, context) { | ||
if(!value && !oldValue) return; | ||
if(element.createShadowRoot) { | ||
var bindData = getBindData(element), | ||
contentClass = bindData.contentClass, | ||
oldElement = bindData.element, | ||
rootElement = context.$rootElement; | ||
if(!oldElement) { | ||
if(_.isString(value)) { | ||
element = document.createElement('div'); | ||
element.innerHTML = value; | ||
} else if(_.isElement(value)) { | ||
element = value; | ||
} else if(_.isElement(value.element)) { | ||
element = value.element; | ||
} | ||
if(element.classList) element.classList.add(contentClass); | ||
else element.className += ' '+contentClass; | ||
bindData.element = element; | ||
DOM.getData(element).$bindContext = context; | ||
rootElement.appendChild(element); | ||
} else { | ||
if(value != oldValue) { | ||
// need to update the content | ||
if(!value) { | ||
// remove old value | ||
DOM.getData(oldElement).$bindContext = null; | ||
rootElement.removeChild(oldElement); | ||
bindData.element = null; | ||
} else if(_.isString(value)) { | ||
// this is the only instance where we need to check the old values type | ||
if(_.isString(oldValue)) { | ||
// easy, just replace the old content with the new one | ||
oldElement.innerHTML = value; | ||
} else { | ||
// need to create a new container element | ||
element = document.createElement('div'); | ||
element.innerHTML = value; | ||
if(element.classList) element.classList.add(contentClass); | ||
else element.className += ' '+contentClass; | ||
bindData.element = element; | ||
DOM.getData(element).$bindContext = context; | ||
DOM.getData(oldElement).$bindContext = null; | ||
rootElement.replaceChild(element, oldElement); | ||
} | ||
} else if(_.isElement(value)) { | ||
if(value.classList) value.classList.add(contentClass); | ||
else value.className += ' '+contentClass; | ||
bindData.element = value; | ||
DOM.getData(value).$bindContext = context; | ||
DOM.getData(oldElement).$bindContext = null; | ||
rootElement.replaceChild(value, oldElement); | ||
} else if(_.isElement(value.element)) { | ||
if(value.element.classList) value.element.classList.add(contentClass); | ||
else value.element.className += ' '+contentClass; | ||
bindData.element = value.element; | ||
DOM.getData(value.element).$bindContext = context; | ||
DOM.getData(oldElement).$bindContext = null; | ||
rootElement.replaceChild(value.element, oldElement); | ||
} | ||
} | ||
} | ||
return; | ||
} | ||
if(_.isString(value)) { | ||
// use text | ||
if('innerHTML' in element) { | ||
element.innerHTML = value; | ||
} else { | ||
DOM.setTextContent(element, value); | ||
} | ||
} else if(!value) { | ||
DOM.removeChildren(element); | ||
} else if(_.isElement(value)) { | ||
DOM.removeChildren(element); | ||
element.appendChild(value); | ||
} else if(_.isElement(value.element)) { // assume we're working with a jide.js Component | ||
DOM.removeChildren(element); | ||
element.appendChild(value.element); | ||
} | ||
} | ||
}, | ||
attr: { | ||
update: function(element, value, oldValue, context) { | ||
oldValue || (oldValue = {}); | ||
var names = Object.getOwnPropertyNames(value); | ||
for(var i = 0, len = names.length; i < len; i++) { | ||
var name = names[i], | ||
attributeValue = Observable.unwrap(value[name]); | ||
if(attributeValue === false || attributeValue === null || attributeValue === undefined) { | ||
element.removeAttribute(name); | ||
} else { | ||
element.setAttribute(name, String(attributeValue)); | ||
} | ||
} | ||
names = Object.getOwnPropertyNames(oldValue); | ||
for(i = 0, len = names.length; i < len; i++) { | ||
if(!value.hasOwnProperty(names[i])) { | ||
element.removeAttribute(names[i]); | ||
} | ||
} | ||
} | ||
}, | ||
foreach: { | ||
init: function(element, context) { | ||
var template = element.firstElementChild; | ||
// at this point, the element doesn't have any children left | ||
getBindData(element).template = template; | ||
// if(template) element.removeChild(template); | ||
element.innerHTML = ''; | ||
return true; // controls children | ||
}, | ||
update: function(element, value, oldValue, context) { | ||
var bindData = getBindData(element), | ||
template = bindData.template, | ||
disposables = bindData.disposables || (bindData.disposables = []), | ||
useTemplate = template && template.content; | ||
var frag = document.createDocumentFragment(); | ||
if(Array.isArray(value)) { | ||
for(var i = 0, len = value.length; i < len; i++) { | ||
var item = value[i], | ||
cloned = useTemplate | ||
? template.content.cloneNode(true) | ||
: (item.element || item); | ||
if(useTemplate) disposables[i] = bind.to(cloned, context.$item, item); | ||
frag.appendChild(cloned); | ||
} | ||
} else if(value.on) { | ||
for(var i = 0, len = value.length; i < len; i++) { | ||
var item = value.get(i), | ||
cloned = useTemplate | ||
? template.content.cloneNode(true) | ||
: (item.element || item); | ||
if(useTemplate) disposables[i] = bind.to(cloned, context.$item, item); | ||
frag.appendChild(cloned); | ||
} | ||
value.on('change', function(event) { | ||
var changes = event.enumerator(); | ||
while(changes.moveNext()) { | ||
var change = changes.current; | ||
if(change.isDelete) { | ||
var templateSize = useTemplate ? template.content.childNodes.length : 1; | ||
for(var len = templateSize; 0 < len; len--) { | ||
element.removeChild(element.childNodes[change.index * templateSize]); | ||
} | ||
disposables.splice(change.index, 1).forEach(function(disposable) { | ||
if(disposable) disposable.dispose(); | ||
}); | ||
} else if(change.isInsert) { | ||
var cloned = useTemplate | ||
? template.content.cloneNode(true) | ||
: (change.newValue.element || change.newValue), | ||
templateSize = useTemplate ? template.content.childNodes.length : 1; | ||
if(useTemplate) disposables.splice(change.index, 0, bind.to(cloned, context.$item, change.newValue)); | ||
DOM.insertElementAt(element, cloned, change.index * templateSize); | ||
} else if(change.isUpdate) { | ||
var cloned = useTemplate | ||
? template.content.cloneNode(true) | ||
: (change.newValue.element || change.newValue); | ||
if(useTemplate) { | ||
disposables[change.index].dispose(); | ||
disposables[change.index] = bind.to(cloned, context.$item, change.newValue); | ||
} | ||
var templateSize = useTemplate ? template.content.childNodes.length - 1 : 0; | ||
for(var len = templateSize; 0 < len; len--) { | ||
element.removeChild(element.childNodes[change.index * templateSize]); | ||
} | ||
element.replaceChild(cloned, element.childNodes[change.index * templateSize]); | ||
} | ||
} | ||
}); | ||
} | ||
element.appendChild(frag); | ||
} | ||
}, | ||
on: { | ||
@@ -498,3 +285,3 @@ update: function(element, value, oldValue, context) { | ||
return fn; | ||
}; | ||
} | ||
@@ -501,0 +288,0 @@ function getBindData(element) { |
@@ -262,8 +262,13 @@ /** | ||
emit: function(name, data) { | ||
emit: function(name, eventData) { | ||
if(!this.element || arguments.length > 2) { | ||
EventEmitter.prototype.emit.apply(this, arguments); | ||
} else { | ||
var event = document.createEvent('Event'); | ||
data || (data = { bubbles: true, cancelable: true }); | ||
if(eventData && ('bubbles' in eventData) && !eventData.bubbles) { | ||
if(EventEmitter.listenerCount(this, name) === 0) return; | ||
EventEmitter.prototype.emit.call(this, name, eventData); | ||
return; | ||
} | ||
var event = document.createEvent('Event'), | ||
data = eventData || {}; | ||
event.initEvent(name, 'bubbles' in data ? data.bubbles : true, 'cancelable' in data ? data.cancelable : true); | ||
@@ -454,3 +459,7 @@ delete data.bubbles; | ||
} else if(Var.is(source[name]) && (name+'Property') in target) { | ||
target[name+'Property'].bind(source[name]); | ||
if(source[name].writable) { | ||
target[name+'Property'].bindBidirectional(source[name]); | ||
} else { | ||
target[name+'Property'].bind(source[name]); | ||
} | ||
} else { | ||
@@ -457,0 +466,0 @@ target[name] = Var.unwrap(source[name]); |
@@ -63,3 +63,3 @@ /** | ||
element.removeChild(child); | ||
} else if(child.hasAtrribute && child.hasAttribute('data-property')) { | ||
} else if(child.hasAttribute && child.hasAttribute('data-property')) { | ||
config[child.getAttribute('data-property')] = child; | ||
@@ -66,0 +66,0 @@ element.removeChild(child); |
@@ -35,3 +35,2 @@ /** | ||
if(!config) config = {}; | ||
if(!config.skin && !config.element) config.element = document.createElement('button'); | ||
ButtonBase.call(this, config); | ||
@@ -41,5 +40,7 @@ this.classList.add('jide-button'); | ||
Class(Button).extends(ButtonBase); | ||
Button.Skin = Skin.create(ButtonBase.Skin); | ||
Button.Skin = Skin.create(ButtonBase.Skin, { | ||
defaultElement: 'button' | ||
}); | ||
register('jide-button', Button, ButtonBase); | ||
return Button; | ||
}); |
@@ -54,3 +54,2 @@ /** | ||
config = _.defaults(config || {}, { tabIndex: 0 }); | ||
if(!config.skin) config.skin = new ButtonBase.Skin(this, config.element); | ||
Labeled.call(this, config); | ||
@@ -57,0 +56,0 @@ this.classList.add('jide-buttonbase'); |
@@ -98,3 +98,2 @@ /** | ||
config || (config = {}); | ||
if(!config.skin) config.skin = new Cell.Skin(this, config.element); | ||
Labeled.call(this, config); | ||
@@ -101,0 +100,0 @@ |
@@ -34,3 +34,2 @@ /** | ||
config || (config = {}); | ||
if(!config.skin) config.skin = new CheckBox.Skin(this, config.element); | ||
ButtonBase.call(this, config); | ||
@@ -37,0 +36,0 @@ Toggle.call(this); |
@@ -20,3 +20,2 @@ /** | ||
config || (config = {}); | ||
config.skin || (config.skin = new CheckBoxMenuItem.Skin(this, config.element)); | ||
CheckBox.call(this, config); | ||
@@ -23,0 +22,0 @@ this.classList.add('jide-checkboxmenuitem'); |
@@ -47,2 +47,3 @@ /** | ||
install: function() { | ||
Skin.prototype.install.call(this); | ||
var choiceBox = this.component; | ||
@@ -64,4 +65,2 @@ var listView = this.listView = new ListView({ | ||
var element = this.element; | ||
var label = element.firstChild; | ||
var button = element.lastChild; | ||
@@ -120,3 +119,2 @@ this.managed( | ||
config = _.defaults(config || {}, { tabIndex: 0 }); | ||
if(!config.skin) config.skin = new ChoiceBox.Skin(this, config.element); | ||
@@ -128,3 +126,3 @@ if(!config.items) this.items = new ObservableList(); | ||
SelectionMixin.call(this, config, this.items); | ||
SelectionMixin.call(this, config, this.items, true); | ||
this.selectionModel = config.selectionModel; | ||
@@ -131,0 +129,0 @@ delete config.selectionModel; |
@@ -84,3 +84,2 @@ /** | ||
config = _.defaults(config || {}, { tabIndex: 0 }); | ||
if(!config.skin) config.skin = new ComboBoxSkin(this, config.element); | ||
@@ -136,4 +135,5 @@ ComboBoxBase.call(this, config); | ||
var installer = Observable.install(ComboBox, 'cellFactory'); | ||
ComboBox.Skin = ComboBoxSkin; | ||
register('jide-combobox', ComboBox, ComboBoxBase, ['cellFactory'], []); | ||
return ComboBox; | ||
}); |
@@ -126,3 +126,2 @@ /** | ||
config = _.defaults(config || {}, { tabIndex: 0 }); | ||
if(!config.skin) config.skin = new ComboBoxBaseSkin(this, config.element); | ||
@@ -129,0 +128,0 @@ if(!config.items) this.items = new ObservableList(); |
@@ -44,5 +44,2 @@ /** | ||
config = config || {}; | ||
if(!config.skin) { | ||
config.skin = new Hyperlink.Skin(this, config.element); | ||
} | ||
ButtonBase.call(this, config); | ||
@@ -49,0 +46,0 @@ this.classList.add('jide-hyperlink'); |
@@ -47,5 +47,2 @@ /** | ||
} | ||
if(!config.skin) { | ||
config.skin = new ImageViewSkin(this, config.element); | ||
} | ||
Control.call(this, config); | ||
@@ -72,2 +69,3 @@ } | ||
var installer = Observable.install(ImageView, 'src'); | ||
ImageView.Skin = ImageViewSkin; | ||
register('jide-imageview', ImageView, Control, ['src'], []); | ||
@@ -74,0 +72,0 @@ |
@@ -19,5 +19,2 @@ /** | ||
config = config || {}; | ||
if(!config.skin) { | ||
config.skin = new Label.Skin(this, config.element); | ||
} | ||
Labeled.call(this, config); | ||
@@ -24,0 +21,0 @@ this.classList.add('jide-label'); |
@@ -23,5 +23,2 @@ /** | ||
config = config || {}; | ||
if(!config.skin) { | ||
config.skin = new Labeled.Skin(this, config.element); | ||
} | ||
Control.call(this, config); | ||
@@ -28,0 +25,0 @@ |
@@ -207,3 +207,2 @@ /** | ||
config = _.defaults(config || {}, { tabIndex: 0 }); | ||
if(!config.skin) config.skin = new ListViewSkin(this, config.element); | ||
@@ -296,4 +295,5 @@ if(!config.items) this.items = new ObservableList(); | ||
var installer = Observable.install(ListView, 'orientation', 'converter', 'cellFactory'); | ||
ListView.Skin = ListViewSkin; | ||
register('jide-listview', ListView, Control, ['orientation', 'converter', 'cellFactory', 'selectionModel', 'items'], []); | ||
return ListView; | ||
}); |
@@ -85,2 +85,3 @@ /** | ||
var installer = Observable.install(Menu, 'showing'); | ||
Menu.Skin = Labeled.Skin; | ||
register('jide-menu', Menu, Labeled, ['showing'], ['show']); | ||
@@ -87,0 +88,0 @@ |
@@ -139,2 +139,3 @@ /** | ||
}); | ||
MenuBar.Skin = MenuBarSkin; | ||
@@ -141,0 +142,0 @@ register('jide-menubar', MenuBar, Control, [], []); |
@@ -24,4 +24,5 @@ /** | ||
Class(MenuItem).extends(ButtonBase); | ||
MenuItem.Skin = ButtonBase.Skin; | ||
register('jide-menuitem', MenuItem, ButtonBase, [], []); | ||
return MenuItem; | ||
}); |
@@ -25,2 +25,3 @@ /** | ||
dispose: function() { | ||
if(this.popup) this.popup.dispose(); | ||
Button.prototype.dispose.call(this); | ||
@@ -69,3 +70,3 @@ installer.dispose(this); | ||
} | ||
popup.setLocation(this.component, Pos.BOTTOM); | ||
popup.show(this.component, Pos.BOTTOM); | ||
} | ||
@@ -75,2 +76,3 @@ if(showing) { | ||
} else { | ||
if(popup) popup.visible = false; | ||
document.body.removeEventListener('click', this.autoHideHandler, true); | ||
@@ -84,4 +86,4 @@ } | ||
this.managed(this.component.showingProperty.subscribe(this.togglePopupVisibility, this)); | ||
if(this.showing) { | ||
this.managed(this.component.showingProperty.subscribe(this.togglePopupVisibility).bind(this)); | ||
if(this.component.showing) { | ||
var popup = this.popup; | ||
@@ -94,11 +96,11 @@ if(popup) { | ||
} | ||
popup.setLocation(this, Pos.BOTTOM); | ||
popup.show(this, Pos.BOTTOM); | ||
} | ||
document.body.addEventListener('click', this.autoHideHandler, true); | ||
} | ||
this.managed(this.on('action', this.toggleShowing).bind(this)); | ||
this.managed(this.component.on('action', this.toggleShowing).bind(this)); | ||
}, | ||
toggleShowing: function() { | ||
this.showing = !this.showing; | ||
this.component.showing = !this.component.showing; | ||
} | ||
@@ -105,0 +107,0 @@ }); |
@@ -98,3 +98,3 @@ /** | ||
Dispatcher.invokeLater(function() { | ||
this.focus(); | ||
if(this && this.element) this.focus(); | ||
}, this); | ||
@@ -101,0 +101,0 @@ if(popup.autoHide) { |
@@ -71,5 +71,2 @@ /** | ||
config = config || {}; | ||
if(!config.skin) { | ||
config.skin = new ProgressBarSkin(this, config.element); | ||
} | ||
Control.call(this, config); | ||
@@ -108,3 +105,4 @@ this.classList.add('jide-progressbar'); | ||
var installer = Observable.install(ProgressBar, 'indeterminate', 'progress'); | ||
ProgressBar.Skin = ProgressBarSkin; | ||
return ProgressBar; | ||
}); |
@@ -87,4 +87,5 @@ /** | ||
}); | ||
RadioButton.Skin = ButtonBase.Skin; | ||
return RadioButton; | ||
}); |
@@ -21,3 +21,4 @@ /** | ||
Class(RadioButtonMenuItem).extends(RadioButton); | ||
RadioButtonMenuItem.Skin = RadioButton.Skin; | ||
return RadioButtonMenuItem; | ||
}); |
@@ -53,5 +53,2 @@ /** | ||
config = config || {}; | ||
if(!config.skin) { | ||
config.skin = new SeparatorSkin(this, config.element); | ||
} | ||
Control.call(this, config); | ||
@@ -58,0 +55,0 @@ this.classList.add('jide-separator'); |
@@ -27,5 +27,2 @@ /** | ||
config = config || {}; | ||
if(!config.skin) { | ||
config.skin = new SVGViewSkin(this, config.element); | ||
} | ||
installer(this); | ||
@@ -88,3 +85,4 @@ Control.call(this, config); | ||
var installer = Observable.install(SVGView, 'content'); | ||
SVGView.Skin = SVGViewSkin; | ||
return SVGView; | ||
}); |
@@ -59,3 +59,5 @@ /** | ||
ToggleButton.Skin = ButtonBase.Skin; | ||
return ToggleButton; | ||
}); |
@@ -18,4 +18,24 @@ /** | ||
var cache = {}; | ||
var cache = {}, needsCloneNodeFix = (function() { | ||
// as far as I know, IE is the only current browser | ||
// that actually needs this fix, but still... | ||
if(has('templateElement')) return false; | ||
var a = document.createElement('template'), | ||
b = document.createElement('template'), | ||
aFrag = document.createDocumentFragment(), | ||
bFrag = document.createDocumentFragment(); | ||
bFrag.appendChild(document.createTextNode('test')); | ||
b.content = bFrag; | ||
aFrag.appendChild(b); | ||
a.content = aFrag; | ||
var clone = a.content.cloneNode(); | ||
if(!clone.firstElementChild) return true; | ||
if(!clone.firstElementChild.content) return true; | ||
return false; | ||
}()); | ||
template.needsCloneNodeFix = needsCloneNodeFix; | ||
function transformStringToElement(templateContent) { | ||
@@ -34,6 +54,15 @@ var div = document.createElement('div'); | ||
if(has('classList')) { | ||
pseudo.classList.add(pseudoId); | ||
if(!pseudo.classList) { | ||
// special case to support SVG elements | ||
if(typeof pseudo.className.baseVal !== 'undefined') { | ||
pseudo.className.baseVal += ' '+pseudoId; | ||
} | ||
} else { | ||
pseudo.classList.add(pseudoId); | ||
} | ||
} else if(typeof pseudo.className.baseVal !== 'undefined') { | ||
pseudo.className.baseVal += ' '+pseudoId; | ||
} else { | ||
pseudo.className += ' '+pseudoId; | ||
} | ||
pseudo.className += ' '+pseudoId; | ||
} | ||
} | ||
@@ -47,7 +76,10 @@ } | ||
} | ||
e.content = frag; | ||
e.content = frag; | ||
} | ||
function rewriteTemplateElements(template) { | ||
if(!template.content) removeContentFromDOM(template); | ||
if(!template.content) { | ||
removeContentFromDOM(template); | ||
if(needsCloneNodeFix) fixCloneNode(template); | ||
} | ||
if(!has('shadowDOM')) addPseudoClass(template); | ||
@@ -57,3 +89,6 @@ var templates = template.content.querySelectorAll('template'); | ||
var e = templates[i]; | ||
if(!e.content) removeContentFromDOM(e); | ||
if(!e.content) { | ||
removeContentFromDOM(e); | ||
if(needsCloneNodeFix) fixCloneNode(e); | ||
} | ||
if(!has('shadowDOM')) { | ||
@@ -66,2 +101,16 @@ addPseudoClass(e); | ||
var originalCloneNode = document.createDocumentFragment().cloneNode; | ||
function fixCloneNode(e) { | ||
var originalTemplates = e.content.querySelectorAll('template'); | ||
e.content.cloneNode = function(flag) { | ||
var copy = originalCloneNode.call(this, flag); | ||
var templates = copy.querySelectorAll('template'); | ||
for(var i = 0, len = templates.length; i < len; i++) { | ||
var template = templates[i]; | ||
if(!template.content) template.content = originalTemplates[i].content; | ||
} | ||
return copy; | ||
}; | ||
} | ||
/** | ||
@@ -98,3 +147,7 @@ * Converts a string or element into an HTML5 template element or shims it, if the browser doesn't support | ||
template.getContent = function(template) { | ||
return template.content || template.getAttribute('content'); | ||
}; | ||
return template; | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
598047
154
16128
2
41