Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions examples/Gameraww/app/CanvasViewController.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
var utils = require('./Utils');
import fetch from './fetch';

var JSCanvasViewController = UICollectionViewController.extend({
numberOfSectionsInCollectionView: function () {
Expand All @@ -18,10 +18,10 @@ var JSCanvasViewController = UICollectionViewController.extend({

var item = this.items[indexPath.item];

utils.fetch(item["thumbnail"])
.then(data => UIImage.imageWithData.async(UIImage, [data]))
.then(image => imageView.image = image)
.catch(error => console.error(error.toString()));
fetch(item["thumbnail"])
.then(data => UIImage.imageWithData.async(UIImage, [ data ]))
.then(image => imageView.image = image)
.catch(error => console.error(error.toString()));

return cell;
},
Expand Down
10 changes: 5 additions & 5 deletions examples/Gameraww/app/DetailViewController.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
var utils = require('./Utils');
import fetch from './fetch';

var JSDetailViewController = UIViewController.extend({
viewWillAppear: function (animated) {
Expand All @@ -12,10 +12,10 @@ var JSDetailViewController = UIViewController.extend({
url += ".jpg";
}

utils.fetch(url)
.then(data => UIImage.imageWithData.async(UIImage, [data]))
.then(this.setImage.bind(this))
.catch(error => console.error(error));
fetch(url)
.then(data => UIImage.imageWithData.async(UIImage, [ data ]))
.then(this.setImage.bind(this))
.catch(error => console.error(error));

UIViewController.prototype.viewWillAppear.call(this, animated);
},
Expand Down
92 changes: 48 additions & 44 deletions examples/Gameraww/app/MasterViewController.js
Original file line number Diff line number Diff line change
@@ -1,45 +1,45 @@
var utils = require('./Utils');
import fetch from './fetch';

var dateFormatter = new NSDateFormatter();
dateFormatter.locale = NSLocale.currentLocale();
//dateFormatter.dateStyle = NSDateFormatterStyle.NSDateFormatterShortStyle;
//dateFormatter.timeStyle = NSDateFormatterStyle.NSDateFormatterShortStyle;
dateFormatter.doesRelativeDateFormatting = true;

var JSMasterViewController = UITableViewController.extend({
viewDidLoad: function () {
var JSMasterViewController = UITableViewController.extend(
{
viewDidLoad : function() {
UITableViewController.prototype.viewDidLoad.call(this);

this.items = [];

this.refreshControl = new UIRefreshControl();
this.refreshControl.addTargetActionForControlEvents(this, "loadData", UIControlEvents.UIControlEventValueChanged);
this.refreshControl.addTargetActionForControlEvents(
this, "loadData", UIControlEvents.ValueChanged);
this.refreshControl.beginRefreshing();

this.loadData();
},
"aboutPressed:": function (sender) {
},
"aboutPressed:" : function(sender) {
var alertWindow = new UIAlertView();
alertWindow.title = "About";
alertWindow.message = "NativeScript Team";
alertWindow.addButtonWithTitle("OK");
alertWindow.show();
},
numberOfSectionsInTableView: function (tableView) {
return 1;
},
tableViewNumberOfRowsInSection: function (tableView, section) {
},
numberOfSectionsInTableView : function(tableView) { return 1; },
tableViewNumberOfRowsInSection : function(tableView, section) {
return this.items.length;
},
prepareForSegueSender: function (segue, sender) {
},
prepareForSegueSender : function(segue, sender) {
if (segue.identifier == "showDetail") {
var item = this.items[this.tableView.indexPathForSelectedRow.row];
segue.destinationViewController.item = item;
var item = this.items[this.tableView.indexPathForSelectedRow.row];
segue.destinationViewController.item = item;
} else if (segue.identifier == "showCanvas") {
segue.destinationViewController.items = this.items;
segue.destinationViewController.items = this.items;
}
},
tableViewCellForRowAtIndexPath: function (tableView, indexPath) {
},
tableViewCellForRowAtIndexPath : function(tableView, indexPath) {
//log('tableViewCellForRowAtIndexPath');
var cell = tableView.dequeueReusableCellWithIdentifierForIndexPath("Cell", indexPath);

Expand All @@ -53,33 +53,37 @@ var JSMasterViewController = UITableViewController.extend({
detailTextLabel.text = dateFormatter.stringFromDate(created);

var imageView = cell.contentView.viewWithTag(3);
utils.fetch(item["thumbnail"])
.then(data => UIImage.imageWithData.async(UIImage, [data]))
.then(image => imageView.image = image)
.catch(error => console.error(error.toString()));
fetch(item["thumbnail"])
.then(data => UIImage.imageWithData.async(UIImage, [ data ]))
.then(image => imageView.image = image)
.catch(error => console.error(error.toString()));

return cell;
},
tableViewHeightForRowAtIndexPath: function (tableView, indexPath) {
},
tableViewHeightForRowAtIndexPath : function(tableView, indexPath) {
return 44;
},
loadData: function () {
var self = this;
utils.fetch("http://www.reddit.com/r/aww.json?limit=500")
.then(data => {
var jsonString = NSString.alloc().initWithDataEncoding(data, NSUTF8StringEncoding).toString();
var json = JSON.parse(jsonString);
self.items = json.data.children.map(child => child.data);
},
loadData : function() {
fetch("http://www.reddit.com/r/aww.json?limit=500")
.then(data => {
var jsonString =
NSString.alloc()
.initWithDataEncoding(data, NSUTF8StringEncoding)
.toString();
var json = JSON.parse(jsonString);
this.items = json.data.children.map(child => child.data);

self.tableView.reloadData();
self.refreshControl.endRefreshing();
})
.catch(error => console.error(error));
}
}, {
name: "JSMasterViewController",
exposedMethods: {
"loadData": { returns: interop.types.void },
"aboutPressed:": { returns: interop.types.void, params: [UIControl] }
}
});
this.tableView.reloadData();
this.refreshControl.endRefreshing();
})
.catch(error => console.error(error));
}
},
{
name : "JSMasterViewController",
exposedMethods : {
"loadData" : {returns : interop.types.void},
"aboutPressed:" :
{returns : interop.types.void, params : [ UIControl ]}
}
});
22 changes: 0 additions & 22 deletions examples/Gameraww/app/Utils.js

This file was deleted.

15 changes: 15 additions & 0 deletions examples/Gameraww/app/fetch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module.exports = function fetch(path) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would look better with ES6 modules syntax, like the other files.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I explicitly left it like that so that Gameraww can exercise both the ES6 modules and the CommonJS shim.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, we have plenty of tests for require calls, but as you wish.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's easier for me to develop and test out new things in Gameraww 😁 I suppose that as soon as modules are mature enough we can move this to ES6 as well.

var url = NSURL.URLWithString(path);
return new Promise((resolve, reject) => {
var dataTask =
NSURLSession.sharedSession().dataTaskWithURLCompletionHandler(
url, function(data, response, error) {
if (error) {
reject(error);
} else {
resolve(data);
}
});
dataTask.resume();
});
}
6 changes: 3 additions & 3 deletions examples/Gameraww/app/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
require('./CanvasViewController');
require('./DetailViewController');
require('./MasterViewController');
import './CanvasViewController';
import './DetailViewController';
import './MasterViewController';

var TNSAppDelegate = UIResponder.extend({
get window() {
Expand Down
5 changes: 2 additions & 3 deletions src/NativeScript/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ set(HEADER_FILES
inspector/InspectorPageAgent.h
inspector/InspectorTimelineAgent.h
inspector/MimeTypeHelper.h
inspector/SourceProviderManager.h
Interop.h
JSErrors.h
JSWarnings.h
Expand Down Expand Up @@ -95,6 +94,7 @@ set(SOURCE_FILES
Calling/FFIFunctionCall.mm
Calling/FFIFunctionCallback.cpp
GlobalObject.mm
GlobalObject.moduleLoader.mm
inspector/CachedResource.mm
inspector/DomainBackendDispatcher.cpp
inspector/DomainInspectorAgent.cpp
Expand All @@ -103,7 +103,6 @@ set(SOURCE_FILES
inspector/GlobalObjectInspectorController.cpp
inspector/InspectorPageAgent.mm
inspector/InspectorTimelineAgent.cpp
inspector/SourceProviderManager.cpp
Interop.mm
JSErrors.mm
JSWarnings.cpp
Expand Down Expand Up @@ -179,7 +178,6 @@ set(NativeScript_PUBLIC_HEADERS
set(JSFILES
__extends.js
inlineFunctions.js
require.js
)

include_directories("${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/**" "${LIBFFI_INCLUDE_DIR}" "${WEBKIT_INCLUDE_DIRECTORIES}")
Expand Down Expand Up @@ -214,6 +212,7 @@ if(${BUILD_SHARED_LIBS})
libc++.dylib
"-framework UIKit"
"-framework MobileCoreServices"
"-framework Security"
)
elseif(${EMBED_STATIC_DEPENDENCIES})
foreach(_directory ${WEBKIT_LINK_DIRECTORIES})
Expand Down
35 changes: 30 additions & 5 deletions src/NativeScript/GlobalObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <JavaScriptCore/JSGlobalObject.h>
#include <objc/runtime.h>
#include <map>
#include <list>
#include <wtf/Deque.h>

namespace NativeScript {
Expand Down Expand Up @@ -135,15 +136,24 @@ class GlobalObject : public JSC::JSGlobalObject {
return this->_fastEnumerationIteratorStructure.get();
}

void setMicrotaskRunLoopAndMode(CFRunLoopRef runLoop, CFTypeRef mode) {
this->_microtaskRunLoop = runLoop;
this->_microtaskRunLoopMode = mode;
CFRunLoopSourceRef microtaskRunLoopSource() const {
return this->_microtaskRunLoopSource.get();
}

std::list<WTF::RetainPtr<CFRunLoopRef>>& microtaskRunLoops() {
return this->_microtaskRunLoops;
}

void drainMicrotasks();

WTF::Deque<std::map<std::string, std::unique_ptr<ReleasePoolBase>>>& releasePools() {
return this->_releasePools;
}

const JSC::Identifier& commonJSModuleFunctionIdentifier() const {
return this->_commonJSModuleFunctionIdentifier;
}

private:
GlobalObject(JSC::VM& vm, JSC::Structure* structure);

Expand All @@ -153,14 +163,27 @@ class GlobalObject : public JSC::JSGlobalObject {

static void destroy(JSC::JSCell* cell);

WTF::Deque<WTF::RefPtr<JSC::Microtask>> _microtasksQueue;
static void queueTaskToEventLoop(const JSC::JSGlobalObject* globalObject, WTF::PassRefPtr<JSC::Microtask> task);

static JSC::JSInternalPromise* moduleLoaderResolve(JSC::JSGlobalObject* globalObject, JSC::ExecState* execState, JSC::JSValue keyValue, JSC::JSValue referrerValue);

static JSC::JSInternalPromise* moduleLoaderFetch(JSC::JSGlobalObject* globalObject, JSC::ExecState* execState, JSC::JSValue keyValue);

static JSC::JSInternalPromise* moduleLoaderTranslate(JSC::JSGlobalObject* globalObject, JSC::ExecState* execState, JSC::JSValue keyValue, JSC::JSValue sourceValue);

static JSC::JSInternalPromise* moduleLoaderInstantiate(JSC::JSGlobalObject* globalObject, JSC::ExecState* execState, JSC::JSValue keyValue, JSC::JSValue sourceValue);

static JSC::JSValue moduleLoaderEvaluate(JSC::JSGlobalObject* globalObject, JSC::ExecState* execState, JSC::JSValue keyValue, JSC::JSValue moduleRecordValue);

static JSC::EncodedJSValue JSC_HOST_CALL commonJSRequire(JSC::ExecState*);

std::unique_ptr<GlobalObjectInspectorController> _inspectorController;

WTF::String _applicationPath;

WTF::RetainPtr<CFRunLoopRef> _microtaskRunLoop;
WTF::RetainPtr<CFTypeRef> _microtaskRunLoopMode;
std::list<WTF::RetainPtr<CFRunLoopRef>> _microtaskRunLoops;
WTF::RetainPtr<CFRunLoopSourceRef> _microtaskRunLoopSource;

JSC::WriteBarrier<FFICallPrototype> _ffiCallPrototype;
JSC::WriteBarrier<JSC::Structure> _objCMethodCallStructure;
Expand Down Expand Up @@ -195,6 +218,8 @@ class GlobalObject : public JSC::JSGlobalObject {
std::map<const Protocol*, JSC::Strong<ObjCProtocolWrapper>> _objCProtocolWrappers;

WTF::Deque<std::map<std::string, std::unique_ptr<ReleasePoolBase>>> _releasePools;

JSC::Identifier _commonJSModuleFunctionIdentifier;
};
}

Expand Down
35 changes: 25 additions & 10 deletions src/NativeScript/GlobalObject.mm
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@

const unsigned GlobalObject::StructureFlags = OverridesGetOwnPropertySlot | Base::StructureFlags;

const GlobalObjectMethodTable GlobalObject::globalObjectMethodTable = { &allowsAccessFrom, &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptRuntimeFlags, &queueTaskToEventLoop, &shouldInterruptScriptBeforeTimeout, 0, 0, 0, 0, 0 };
const GlobalObjectMethodTable GlobalObject::globalObjectMethodTable = { &allowsAccessFrom, &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptRuntimeFlags, &queueTaskToEventLoop, &shouldInterruptScriptBeforeTimeout, &moduleLoaderResolve, &moduleLoaderFetch, &moduleLoaderTranslate, &moduleLoaderInstantiate, &moduleLoaderEvaluate };

GlobalObject::GlobalObject(VM& vm, Structure* structure)
: JSGlobalObject(vm, structure, &GlobalObject::globalObjectMethodTable) {
Expand All @@ -103,6 +103,12 @@ static EncodedJSValue JSC_HOST_CALL collectGarbage(ExecState* execState) {
return JSValue::encode(jsUndefined());
}

static void microtaskRunLoopSourcePerformWork(void* context) {
GlobalObject* self = static_cast<GlobalObject*>(context);
JSLockHolder lockHolder(self->vm());
self->drainMicrotasks();
}

void GlobalObject::finishCreation(WTF::String applicationPath, VM& vm) {
Base::finishCreation(vm);

Expand Down Expand Up @@ -168,6 +174,12 @@ static EncodedJSValue JSC_HOST_CALL collectGarbage(ExecState* execState) {
NSObjectConstructor->putDirect(vm, vm.propertyNames->toString, constructFunction(globalExec, this, staticDescriptionFunctionArgs), DontEnum);

NSObjectConstructor->setPrototype(vm, NSObjectPrototype);

CFRunLoopSourceContext context = { 0, this, 0, 0, 0, 0, 0, 0, 0, microtaskRunLoopSourcePerformWork };
_microtaskRunLoopSource = WTF::adoptCF(CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context));

_commonJSModuleFunctionIdentifier = Identifier::fromString(&vm, "CommonJSModuleFunction");
this->putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "require"), 1, commonJSRequire, NoIntrinsic, DontEnum | DontDelete | ReadOnly);
}

void GlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor) {
Expand Down Expand Up @@ -388,14 +400,17 @@ static EncodedJSValue JSC_HOST_CALL collectGarbage(ExecState* execState) {
}

void GlobalObject::queueTaskToEventLoop(const JSGlobalObject* globalObject, WTF::PassRefPtr<Microtask> task) {
auto global = jsCast<const GlobalObject*>(globalObject);
CFRunLoopRef runLoop = global->_microtaskRunLoop.get() ?: CFRunLoopGetCurrent();
CFTypeRef mode = global->_microtaskRunLoopMode.get() ?: kCFRunLoopCommonModes;

CFRunLoopPerformBlock(runLoop, mode, ^{
JSLockHolder lock(globalObject->vm());
task->run(const_cast<JSGlobalObject*>(globalObject)->globalExec());
});
CFRunLoopWakeUp(runLoop);
GlobalObject* self = jsCast<GlobalObject*>(const_cast<JSGlobalObject*>(globalObject));
self->_microtasksQueue.append(task);
CFRunLoopSourceSignal(self->_microtaskRunLoopSource.get());
for (auto runLoop : self->microtaskRunLoops()) {
CFRunLoopWakeUp(runLoop.get());
}
}

void GlobalObject::drainMicrotasks() {
while (!this->_microtasksQueue.isEmpty()) {
this->_microtasksQueue.takeFirst()->run(this->globalExec());
}
}
}
Loading