1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qv8include_p.h"
44 #include <QtQml/qjsengine.h>
45 #include <QtNetwork/qnetworkrequest.h>
46 #include <QtNetwork/qnetworkreply.h>
47 #include <QtCore/qfile.h>
49 #include <private/qqmlengine_p.h>
53 QV8Include::QV8Include(const QUrl &url, QV8Engine *engine, QQmlContextData *context,
54 v8::Handle<v8::Object> qmlglobal, v8::Handle<v8::Function> callback)
55 : m_engine(engine), m_network(0), m_reply(0), m_url(url), m_redirectCount(0), m_context(context)
57 m_qmlglobal = qPersistentNew<v8::Object>(qmlglobal);
58 if (!callback.IsEmpty())
59 m_callbackFunction = qPersistentNew<v8::Function>(callback);
61 m_resultObject = qPersistentNew<v8::Object>(resultValue());
63 m_network = engine->networkAccessManager();
65 QNetworkRequest request;
68 m_reply = m_network->get(request);
69 QObject::connect(m_reply, SIGNAL(finished()), this, SLOT(finished()));
72 QV8Include::~QV8Include()
74 delete m_reply; m_reply = 0;
75 qPersistentDispose(m_callbackFunction);
76 qPersistentDispose(m_resultObject);
79 v8::Local<v8::Object> QV8Include::resultValue(Status status)
81 // XXX It seems inefficient to create this object from scratch each time.
82 v8::Local<v8::Object> result = v8::Object::New();
83 result->Set(v8::String::New("OK"), v8::Integer::New(Ok));
84 result->Set(v8::String::New("LOADING"), v8::Integer::New(Loading));
85 result->Set(v8::String::New("NETWORK_ERROR"), v8::Integer::New(NetworkError));
86 result->Set(v8::String::New("EXCEPTION"), v8::Integer::New(Exception));
88 result->Set(v8::String::New("status"), v8::Integer::New(status));
93 void QV8Include::callback(QV8Engine *engine, v8::Handle<v8::Function> callback, v8::Handle<v8::Object> status)
95 if (!callback.IsEmpty()) {
96 v8::Handle<v8::Value> args[] = { status };
98 callback->Call(engine->global(), 1, args);
102 v8::Handle<v8::Object> QV8Include::result()
104 return m_resultObject;
107 #define INCLUDE_MAXIMUM_REDIRECT_RECURSION 15
108 void QV8Include::finished()
112 if (m_redirectCount < INCLUDE_MAXIMUM_REDIRECT_RECURSION) {
113 QVariant redirect = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
114 if (redirect.isValid()) {
115 m_url = m_url.resolved(redirect.toUrl());
118 QNetworkRequest request;
119 request.setUrl(m_url);
121 m_reply = m_network->get(request);
122 QObject::connect(m_reply, SIGNAL(finished()), this, SLOT(finished()));
127 v8::HandleScope handle_scope;
129 if (m_reply->error() == QNetworkReply::NoError) {
130 QByteArray data = m_reply->readAll();
132 QString code = QString::fromUtf8(data);
133 QQmlScript::Parser::extractPragmas(code);
135 QQmlContextData *importContext = new QQmlContextData;
136 importContext->isInternal = true;
137 importContext->isJSContext = true;
138 importContext->url = m_url;
139 importContext->isPragmaLibraryContext = m_context->isPragmaLibraryContext;
140 importContext->setParent(m_context, true);
142 v8::Context::Scope ctxtscope(m_engine->context());
143 v8::TryCatch try_catch;
145 v8::Local<v8::Script> script = m_engine->qmlModeCompile(code, m_url.toString());
147 if (!try_catch.HasCaught()) {
148 m_engine->contextWrapper()->addSubContext(m_qmlglobal, script, importContext);
149 script->Run(m_qmlglobal);
152 if (try_catch.HasCaught()) {
153 m_resultObject->Set(v8::String::New("status"), v8::Integer::New(Exception));
154 m_resultObject->Set(v8::String::New("exception"), try_catch.Exception());
156 m_resultObject->Set(v8::String::New("status"), v8::Integer::New(Ok));
159 m_resultObject->Set(v8::String::New("status"), v8::Integer::New(NetworkError));
162 callback(m_engine, m_callbackFunction, m_resultObject);
169 Documented in qv8engine.cpp
171 v8::Handle<v8::Value> QV8Include::include(const v8::Arguments &args)
173 if (args.Length() == 0)
174 return v8::Undefined();
176 QV8Engine *engine = V8ENGINE();
177 QQmlContextData *context = engine->callingContext();
179 if (!context || !context->isJSContext)
180 V8THROW_ERROR("Qt.include(): Can only be called from JavaScript files");
182 QUrl url(context->resolvedUrl(QUrl(engine->toString(args[0]->ToString()))));
184 v8::Local<v8::Function> callbackFunction;
185 if (args.Length() >= 2 && args[1]->IsFunction())
186 callbackFunction = v8::Local<v8::Function>::Cast(args[1]);
188 QString localFile = QQmlEnginePrivate::urlToLocalFileOrQrc(url);
190 v8::Local<v8::Object> result;
192 if (localFile.isEmpty()) {
194 QV8Include *i = new QV8Include(url, engine, context,
195 v8::Context::GetCallingQmlGlobal(),
197 result = v8::Local<v8::Object>::New(i->result());
203 if (f.open(QIODevice::ReadOnly)) {
204 QByteArray data = f.readAll();
205 QString code = QString::fromUtf8(data);
206 QQmlScript::Parser::extractPragmas(code);
208 QQmlContextData *importContext = new QQmlContextData;
209 importContext->isInternal = true;
210 importContext->isJSContext = true;
211 importContext->url = url;
212 importContext->setParent(context, true);
214 v8::TryCatch try_catch;
216 v8::Local<v8::Script> script = engine->qmlModeCompile(code, url.toString());
218 if (!try_catch.HasCaught()) {
219 v8::Local<v8::Object> qmlglobal = v8::Context::GetCallingQmlGlobal();
220 engine->contextWrapper()->addSubContext(qmlglobal, script, importContext);
221 script->Run(qmlglobal);
224 if (try_catch.HasCaught()) {
225 result = resultValue(Exception);
226 result->Set(v8::String::New("exception"), try_catch.Exception());
228 result = resultValue(Ok);
232 result = resultValue(NetworkError);
235 callback(engine, callbackFunction, result);
238 if (result.IsEmpty())
239 return v8::Undefined();