Fixes #457 and #467 - ready and $ are now optional

This commit is contained in:
Patrick Steele-Idem 2016-12-16 11:39:53 -07:00
parent 6ede2aaa05
commit a9fc85f272
15 changed files with 173 additions and 108 deletions

54
jquery.js vendored Normal file
View File

@ -0,0 +1,54 @@
var ready = require('./ready');
var idRegExp = /^\#(\S+)( .*)?/;
exports.patchWidget = function(jQuery) {
/* globals window */
if (!jQuery) {
jQuery = window.$;
if (!jQuery) {
throw new Error('jQuery not found');
}
}
require('./widgets/Widget').prototype.$ = function jqueryProxy(arg) {
var args = arguments;
var self = this;
if (args.length === 1) {
//Handle an "ondomready" callback function
if (typeof arg === 'function') {
return ready(function() {
arg.call(self);
});
} else if (typeof arg === 'string') {
var match = idRegExp.exec(arg);
//Reset the search to 0 so the next call to exec will start from the beginning for the new string
if (match != null) {
var widgetElId = match[1];
if (match[2] == null) {
return jQuery(self.getEl(widgetElId));
} else {
return jQuery('#' + self.getElId(widgetElId) + match[2]);
}
} else {
var rootEl = self.getEl();
if (!rootEl) {
throw new Error('Root element is not defined for widget');
}
if (rootEl) {
return jQuery(arg, rootEl);
}
}
}
} else if (args.length === 2 && typeof args[1] === 'string') {
return jQuery(arg, self.getEl(args[1]));
} else if (args.length === 0) {
return jQuery(self.el);
}
return jQuery.apply(window, arguments);
};
};

View File

@ -119,7 +119,7 @@ function bindReady(doc) {
}
}
module.exports = function(callback, thisObj, doc) {
function ready(callback, thisObj, doc) {
if (isReady) {
return callback.call(thisObj);
}
@ -130,4 +130,14 @@ module.exports = function(callback, thisObj, doc) {
readyBound = true;
bindReady(doc || defaultDocument);
}
};
}
module.exports = ready;
module.exports.patchWidget = function() {
require('./widgets/Widget').prototype.ready = function (callback) {
var document = this.el.ownerDocument;
ready(callback, this, document);
};
};

View File

@ -20,6 +20,4 @@ module.exports = function(helpers) {
expect(widget.insertBefore).to.be.a('function');
expect(widget.insertAfter).to.be.a('function');
expect(widget.prependTo).to.be.a('function');
expect(widget.ready).to.be.a('function');
expect(widget.$).to.be.a('function');
};

View File

@ -2,10 +2,10 @@ function Widget(config) {
this.label = config.label;
this.name = 'app-bar';
var $el = this.$();
var el = this.el;
this.appendHtml = function(html) {
$el.append(html);
el.innerHTML += html;
};
}

View File

@ -2,10 +2,10 @@ function Widget(config) {
this.label = config.label;
this.name = 'app-bar';
var $el = this.$();
var el = this.el;
this.appendHtml = function(html) {
$el.append(html);
el.innerHTML += html;
};
}

View File

@ -2,10 +2,10 @@ function Widget(config) {
this.label = config.label;
this.name = 'app-bar';
var $el = this.$();
var el = this.el;
this.appendHtml = function(html) {
$el.append(html);
el.innerHTML += html;
};
}

View File

@ -1,28 +1,33 @@
var expect = require('chai').expect;
module.exports = function(helpers, done) {
var widget = helpers.mount(require('./index'), {});
var $el = widget.$();
var $button = widget.$('#button');
require('marko/jquery').patchWidget(window.$);
try {
var widget = helpers.mount(require('./index'), {});
var $el = widget.$();
var $button = widget.$('#button');
$el.click(function() {
helpers.log('$el:click');
});
$el.click(function() {
helpers.log('$el:click');
});
$button.click(function(event) {
event.stopPropagation();
helpers.log('$button:click');
});
$button.click(function(event) {
event.stopPropagation();
helpers.log('$button:click');
});
// Trigger a click event on the root element
helpers.triggerClick(widget.el);
helpers.triggerClick(widget.getEl('button'));
// Trigger a click event on the root element
helpers.triggerClick(widget.el);
helpers.triggerClick(widget.getEl('button'));
expect(helpers.logOutput).to.deep.equal([
'$el:click',
'$button:click'
]);
expect(helpers.logOutput).to.deep.equal([
'$el:click',
'$button:click'
]);
} finally {
delete require('marko/widgets/Widget').prototype.$;
}
done();
};

View File

@ -1,20 +1,27 @@
var expect = require('chai').expect;
module.exports = function(helpers, done) {
var widget = helpers.mount(require('./index'), {});
require('marko/jquery').patchWidget(window.$);
expect(widget.$().attr('id')).to.equal(widget.id);
expect(widget.$().attr('class')).to.equal('app-jquery-proxy');
expect(widget.$('#foo').html()).to.equal('foo');
expect(widget.$('#fooText').html()).to.equal('fooText');
expect(widget.$('#foo-text').html()).to.equal('foo-text');
expect(widget.$('#ul li').length).to.equal(3);
expect(widget.$('button').html()).to.equal('Test Button');
expect(widget.$('li', 'ul').length).to.equal(3);
try {
var widget = helpers.mount(require('./index'), {});
var count = 0;
widget.$(function() {
count++;
done();
});
expect(widget.$().attr('id')).to.equal(widget.id);
expect(widget.$().attr('class')).to.equal('app-jquery-proxy');
expect(widget.$('#foo').html()).to.equal('foo');
expect(widget.$('#fooText').html()).to.equal('fooText');
expect(widget.$('#foo-text').html()).to.equal('foo-text');
expect(widget.$('#ul li').length).to.equal(3);
expect(widget.$('button').html()).to.equal('Test Button');
expect(widget.$('li', 'ul').length).to.equal(3);
var count = 0;
widget.$(function() {
count++;
done();
});
} finally {
delete require('marko/widgets/Widget').prototype.$;
}
};

View File

@ -0,0 +1,7 @@
module.exports = require('marko/widgets').defineComponent({
template: require('./template.marko'),
init: function() {
}
});

View File

@ -0,0 +1 @@
div w-bind

View File

@ -0,0 +1,13 @@
module.exports = function(helpers, done) {
require('marko/ready').patchWidget();
try {
var widget = helpers.mount(require('./index'), {});
widget.ready(function() {
done();
});
} finally {
delete require('marko/widgets/Widget').prototype.ready;
}
};

View File

@ -1,12 +1,15 @@
var path = require('path');
var expect = require('chai').expect;
var markoWidgets = require('marko/widgets');
describe(path.basename(__dirname), function() {
it('should handle ending </script> tag', function(done) {
markoWidgets.ready(function() {
var ready = require('marko/ready');
ready(function() {
expect(window.fooWidget.state.evil).to.equal('</script><script>alert("hello")</script>');
expect(window.fooWidget.widgetConfig.evil).to.equal('</script><script>alert("hello")</script>');
done();

View File

@ -9,16 +9,32 @@ if (typeof window !== 'undefined') {
function run(testFunc, done) {
var helpers = new BrowserHelpers();
if (testFunc.length === 1) {
testFunc(helpers);
helpers._cleanup();
done();
} else {
testFunc(helpers, function(err) {
helpers._cleanup();
done(err);
});
require('marko/jquery').patchWidget(window.$);
require('marko/ready').patchWidget();
function cleanup() {
delete require('marko/widgets/Widget').prototype.$;
delete require('marko/widgets/Widget').prototype.ready;
}
try {
if (testFunc.length === 1) {
testFunc(helpers);
helpers._cleanup();
cleanup();
done();
} else {
testFunc(helpers, function(err) {
helpers._cleanup();
cleanup();
done(err);
});
}
} catch(e) {
cleanup();
throw e;
}
});
});
}

View File

@ -21,7 +21,6 @@ var NON_WIDGET_SUBSCRIBE_TO_OPTIONS = {
var emit = EventEmitter.prototype.emit;
var idRegExp = /^\#(\S+)( .*)?/;
var lifecycleEventMethods = {
'beforeDestroy': 'onBeforeDestroy',
@ -150,7 +149,7 @@ function handleCustomEventWithMethodListener(widget, targetMethodName, args, ext
targetMethod.apply(targetWidget, args);
}
function getElId(widget, widgetElId, index) {
function getElIdHelper(widget, widgetElId, index) {
var id = widget.id;
var elId = widgetElId != null ? id + '-' + widgetElId : id;
@ -278,15 +277,15 @@ Widget.prototype = widgetProto = {
return emit.apply(this, arguments);
},
getElId: function (widgetElId, index) {
return getElId(this, widgetElId, index);
return getElIdHelper(this, widgetElId, index);
},
getEl: function (widgetElId, index) {
var doc = this.__document;
if (widgetElId != null) {
return doc.getElementById(getElId(this, widgetElId, index));
return doc.getElementById(getElIdHelper(this, widgetElId, index));
} else {
return this.el || doc.getElementById(getElId(this));
return this.el || doc.getElementById(getElIdHelper(this));
}
},
getEls: function(id) {
@ -303,7 +302,7 @@ Widget.prototype = widgetProto = {
return els;
},
getWidget: function(id, index) {
var targetWidgetId = getElId(this, id, index);
var targetWidgetId = getElIdHelper(this, id, index);
return widgetLookup[targetWidgetId];
},
getWidgets: function(id) {
@ -623,49 +622,6 @@ Widget.prototype = widgetProto = {
resetWidget(self);
}
});
},
ready: function (callback) {
var document = this.el.ownerDocument;
markoWidgets.ready(callback, this, document);
},
$: function (arg) {
var jquery = markoWidgets.$;
var args = arguments;
if (args.length === 1) {
//Handle an "ondomready" callback function
if (typeof arg === 'function') {
var _this = this;
return _this.ready(function() {
arg.call(_this);
});
} else if (typeof arg === 'string') {
var match = idRegExp.exec(arg);
//Reset the search to 0 so the next call to exec will start from the beginning for the new string
if (match != null) {
var widgetElId = match[1];
if (match[2] == null) {
return jquery(this.getEl(widgetElId));
} else {
return jquery('#' + getElId(this, widgetElId) + match[2]);
}
} else {
var rootEl = this.getEl();
if (!rootEl) {
throw new Error('Root element is not defined for widget');
}
if (rootEl) {
return jquery(arg, rootEl);
}
}
}
} else if (args.length === 2 && typeof args[1] === 'string') {
return jquery(arg, this.getEl(args[1]));
} else if (args.length === 0) {
return jquery(this.el);
}
return jquery.apply(window, arguments);
}
};

View File

@ -1,13 +1,12 @@
var ready = require('../runtime/ready');
var Widget = require('./Widget');
var initServerRendered = require('./init-widgets').initServerRendered;
var updateManager = require('./update-manager');
var events = require('../runtime/events');
var WidgetsContext = exports.WidgetsContext = require('./WidgetsContext');
exports.getWidgetsContext = WidgetsContext.getWidgetsContext;
exports.Widget = Widget;
exports.ready = ready;
exports.onInitWidget = function(listener) {
events.on('initWidget', listener);
};
@ -83,10 +82,6 @@ events.on('dom/beforeRemove', function(eventArgs) {
exports.initWidgets = initServerRendered;
var jquery = window.$;
exports.$ = jquery;
exports.registerWidget = require('./registry').register;
exports.defineComponent = require('./defineComponent'); // Deprecated
exports.defineWidget /* deprecated */ = exports.w = require('./defineWidget');