khtml Library API Documentation

kjs_window.cpp

00001 // -*- c-basic-offset: 2 -*- 00002 /* 00003 * This file is part of the KDE libraries 00004 * Copyright (C) 2000-2003 Harri Porten (porten@kde.org) 00005 * Copyright (C) 2001-2003 David Faure (faure@kde.org) 00006 * Copyright (C) 2003 Apple Computer, Inc. 00007 * 00008 * This library is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Library General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2 of the License, or (at your option) any later version. 00012 * 00013 * This library is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Library General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Library General Public 00019 * License along with this library; if not, write to the Free Software 00020 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00021 */ 00022 #include "config.h" 00023 00024 #include <qstylesheet.h> 00025 #include <qtimer.h> 00026 #include <qpaintdevicemetrics.h> 00027 #include <qapplication.h> 00028 #include <kdebug.h> 00029 #include <kmessagebox.h> 00030 #include <kinputdialog.h> 00031 #include <klocale.h> 00032 #include <kparts/browserinterface.h> 00033 #include <kwin.h> 00034 00035 #if defined Q_WS_X11 && ! defined K_WS_QTONLY 00036 #include <kwinmodule.h> // schroder 00037 #endif 00038 00039 #include <kbookmarkmanager.h> 00040 #include <kglobalsettings.h> 00041 #include <assert.h> 00042 #include <qstyle.h> 00043 #include <qobjectlist.h> 00044 #include <kstringhandler.h> 00045 00046 #include "kjs_proxy.h" 00047 #include "kjs_window.h" 00048 #include "kjs_navigator.h" 00049 #include "kjs_mozilla.h" 00050 #include "kjs_html.h" 00051 #include "kjs_range.h" 00052 #include "kjs_traversal.h" 00053 #include "kjs_css.h" 00054 #include "kjs_events.h" 00055 #include "xmlhttprequest.h" 00056 #include "xmlserializer.h" 00057 00058 #include "khtmlview.h" 00059 #include "khtml_part.h" 00060 #include "khtml_settings.h" 00061 #include "xml/dom2_eventsimpl.h" 00062 #include "xml/dom_docimpl.h" 00063 #include "misc/htmltags.h" 00064 #include "html/html_documentimpl.h" 00065 00066 using namespace KJS; 00067 00068 namespace KJS { 00069 00070 class History : public ObjectImp { 00071 friend class HistoryFunc; 00072 public: 00073 History(ExecState *exec, KHTMLPart *p) 00074 : ObjectImp(exec->interpreter()->builtinObjectPrototype()), part(p) { } 00075 virtual Value get(ExecState *exec, const Identifier &propertyName) const; 00076 Value getValueProperty(ExecState *exec, int token) const; 00077 virtual const ClassInfo* classInfo() const { return &info; } 00078 static const ClassInfo info; 00079 enum { Back, Forward, Go, Length }; 00080 private: 00081 QGuardedPtr<KHTMLPart> part; 00082 }; 00083 00084 class External : public ObjectImp { 00085 friend class ExternalFunc; 00086 public: 00087 External(ExecState *exec, KHTMLPart *p) 00088 : ObjectImp(exec->interpreter()->builtinObjectPrototype()), part(p) { } 00089 virtual Value get(ExecState *exec, const Identifier &propertyName) const; 00090 virtual const ClassInfo* classInfo() const { return &info; } 00091 static const ClassInfo info; 00092 enum { AddFavorite }; 00093 private: 00094 QGuardedPtr<KHTMLPart> part; 00095 }; 00096 00097 class FrameArray : public ObjectImp { 00098 public: 00099 FrameArray(ExecState *exec, KHTMLPart *p) 00100 : ObjectImp(exec->interpreter()->builtinObjectPrototype()), part(p) { } 00101 virtual Value get(ExecState *exec, const Identifier &propertyName) const; 00102 private: 00103 QGuardedPtr<KHTMLPart> part; 00104 }; 00105 00106 #ifdef Q_WS_QWS 00107 class KonquerorFunc : public DOMFunction { 00108 public: 00109 KonquerorFunc(const Konqueror* k, const char* name) 00110 : DOMFunction(), konqueror(k), m_name(name) { } 00111 virtual Value tryCall(ExecState *exec, Object &thisObj, const List &args); 00112 00113 private: 00114 const Konqueror* konqueror; 00115 QCString m_name; 00116 }; 00117 #endif 00118 } // namespace KJS 00119 00120 #include "kjs_window.lut.h" 00121 #include "rendering/render_replaced.h" 00122 00124 00125 // table for screen object 00126 /* 00127 @begin ScreenTable 7 00128 height Screen::Height DontEnum|ReadOnly 00129 width Screen::Width DontEnum|ReadOnly 00130 colorDepth Screen::ColorDepth DontEnum|ReadOnly 00131 pixelDepth Screen::PixelDepth DontEnum|ReadOnly 00132 availLeft Screen::AvailLeft DontEnum|ReadOnly 00133 availTop Screen::AvailTop DontEnum|ReadOnly 00134 availHeight Screen::AvailHeight DontEnum|ReadOnly 00135 availWidth Screen::AvailWidth DontEnum|ReadOnly 00136 @end 00137 */ 00138 00139 const ClassInfo Screen::info = { "Screen", 0, &ScreenTable, 0 }; 00140 00141 // We set the object prototype so that toString is implemented 00142 Screen::Screen(ExecState *exec) 00143 : ObjectImp(exec->interpreter()->builtinObjectPrototype()) {} 00144 00145 Value Screen::get(ExecState *exec, const Identifier &p) const 00146 { 00147 #ifdef KJS_VERBOSE 00148 kdDebug(6070) << "Screen::get " << p.qstring() << endl; 00149 #endif 00150 return lookupGetValue<Screen,ObjectImp>(exec,p,&ScreenTable,this); 00151 } 00152 00153 Value Screen::getValueProperty(ExecState *exec, int token) const 00154 { 00155 #if defined Q_WS_X11 && ! defined K_WS_QTONLY 00156 KWinModule info(0, KWinModule::INFO_DESKTOP); 00157 #endif 00158 QWidget *thisWidget = Window::retrieveActive(exec)->part()->view(); 00159 QRect sg = KGlobalSettings::desktopGeometry(thisWidget); 00160 00161 switch( token ) { 00162 case Height: 00163 return Number(sg.height()); 00164 case Width: 00165 return Number(sg.width()); 00166 case ColorDepth: 00167 case PixelDepth: { 00168 QPaintDeviceMetrics m(QApplication::desktop()); 00169 return Number(m.depth()); 00170 } 00171 case AvailLeft: { 00172 #if defined Q_WS_X11 && ! defined K_WS_QTONLY 00173 QRect clipped = info.workArea().intersect(sg); 00174 return Number(clipped.x()-sg.x()); 00175 #else 00176 return Number(10); 00177 #endif 00178 } 00179 case AvailTop: { 00180 #if defined Q_WS_X11 && ! defined K_WS_QTONLY 00181 QRect clipped = info.workArea().intersect(sg); 00182 return Number(clipped.y()-sg.y()); 00183 #else 00184 return Number(10); 00185 #endif 00186 } 00187 case AvailHeight: { 00188 #if defined Q_WS_X11 && ! defined K_WS_QTONLY 00189 QRect clipped = info.workArea().intersect(sg); 00190 return Number(clipped.height()); 00191 #else 00192 return Number(100); 00193 #endif 00194 } 00195 case AvailWidth: { 00196 #if defined Q_WS_X11 && ! defined K_WS_QTONLY 00197 QRect clipped = info.workArea().intersect(sg); 00198 return Number(clipped.width()); 00199 #else 00200 return Number(100); 00201 #endif 00202 } 00203 default: 00204 kdDebug(6070) << "WARNING: Screen::getValueProperty unhandled token " << token << endl; 00205 return Undefined(); 00206 } 00207 } 00208 00210 00211 const ClassInfo Window::info = { "Window", 0, &WindowTable, 0 }; 00212 00213 /* 00214 @begin WindowTable 87 00215 closed Window::Closed DontDelete|ReadOnly 00216 crypto Window::Crypto DontDelete|ReadOnly 00217 defaultStatus Window::DefaultStatus DontDelete 00218 defaultstatus Window::DefaultStatus DontDelete 00219 status Window::Status DontDelete 00220 document Window::Document DontDelete|ReadOnly 00221 Node Window::Node DontDelete 00222 Event Window::EventCtor DontDelete 00223 Range Window::Range DontDelete 00224 NodeFilter Window::NodeFilter DontDelete 00225 DOMException Window::DOMException DontDelete 00226 CSSRule Window::CSSRule DontDelete 00227 frames Window::Frames DontDelete|ReadOnly 00228 history Window::_History DontDelete|ReadOnly 00229 external Window::_External DontDelete|ReadOnly 00230 event Window::Event DontDelete|ReadOnly 00231 innerHeight Window::InnerHeight DontDelete|ReadOnly 00232 innerWidth Window::InnerWidth DontDelete|ReadOnly 00233 length Window::Length DontDelete|ReadOnly 00234 location Window::_Location DontDelete 00235 name Window::Name DontDelete 00236 navigator Window::_Navigator DontDelete|ReadOnly 00237 clientInformation Window::ClientInformation DontDelete|ReadOnly 00238 konqueror Window::_Konqueror DontDelete|ReadOnly 00239 offscreenBuffering Window::OffscreenBuffering DontDelete|ReadOnly 00240 opener Window::Opener DontDelete|ReadOnly 00241 outerHeight Window::OuterHeight DontDelete|ReadOnly 00242 outerWidth Window::OuterWidth DontDelete|ReadOnly 00243 pageXOffset Window::PageXOffset DontDelete|ReadOnly 00244 pageYOffset Window::PageYOffset DontDelete|ReadOnly 00245 parent Window::Parent DontDelete|ReadOnly 00246 personalbar Window::Personalbar DontDelete|ReadOnly 00247 screenX Window::ScreenX DontDelete|ReadOnly 00248 screenY Window::ScreenY DontDelete|ReadOnly 00249 scrollbars Window::Scrollbars DontDelete|ReadOnly 00250 scroll Window::Scroll DontDelete|Function 2 00251 scrollBy Window::ScrollBy DontDelete|Function 2 00252 scrollTo Window::ScrollTo DontDelete|Function 2 00253 moveBy Window::MoveBy DontDelete|Function 2 00254 moveTo Window::MoveTo DontDelete|Function 2 00255 resizeBy Window::ResizeBy DontDelete|Function 2 00256 resizeTo Window::ResizeTo DontDelete|Function 2 00257 self Window::Self DontDelete|ReadOnly 00258 window Window::_Window DontDelete|ReadOnly 00259 top Window::Top DontDelete|ReadOnly 00260 screen Window::_Screen DontDelete|ReadOnly 00261 Image Window::Image DontDelete|ReadOnly 00262 Option Window::Option DontDelete|ReadOnly 00263 XMLHttpRequest Window::XMLHttpRequest DontDelete|ReadOnly 00264 XMLSerializer Window::XMLSerializer DontDelete|ReadOnly 00265 alert Window::Alert DontDelete|Function 1 00266 confirm Window::Confirm DontDelete|Function 1 00267 prompt Window::Prompt DontDelete|Function 2 00268 open Window::Open DontDelete|Function 3 00269 setTimeout Window::SetTimeout DontDelete|Function 2 00270 clearTimeout Window::ClearTimeout DontDelete|Function 1 00271 focus Window::Focus DontDelete|Function 0 00272 blur Window::Blur DontDelete|Function 0 00273 close Window::Close DontDelete|Function 0 00274 setInterval Window::SetInterval DontDelete|Function 2 00275 clearInterval Window::ClearInterval DontDelete|Function 1 00276 captureEvents Window::CaptureEvents DontDelete|Function 0 00277 releaseEvents Window::ReleaseEvents DontDelete|Function 0 00278 print Window::Print DontDelete|Function 0 00279 addEventListener Window::AddEventListener DontDelete|Function 3 00280 removeEventListener Window::RemoveEventListener DontDelete|Function 3 00281 # IE extension 00282 navigate Window::Navigate DontDelete|Function 1 00283 # Mozilla extension 00284 sidebar Window::SideBar DontDelete|ReadOnly 00285 00286 # Warning, when adding a function to this object you need to add a case in Window::get 00287 00288 # Event handlers 00289 # IE also has: onactivate, onbefore/afterprint, onbeforedeactivate/unload, oncontrolselect, 00290 # ondeactivate, onhelp, onmovestart/end, onresizestart/end, onscroll. 00291 # It doesn't have onabort, onchange, ondragdrop (but NS has that last one). 00292 onabort Window::Onabort DontDelete 00293 onblur Window::Onblur DontDelete 00294 onchange Window::Onchange DontDelete 00295 onclick Window::Onclick DontDelete 00296 ondblclick Window::Ondblclick DontDelete 00297 ondragdrop Window::Ondragdrop DontDelete 00298 onerror Window::Onerror DontDelete 00299 onfocus Window::Onfocus DontDelete 00300 onkeydown Window::Onkeydown DontDelete 00301 onkeypress Window::Onkeypress DontDelete 00302 onkeyup Window::Onkeyup DontDelete 00303 onload Window::Onload DontDelete 00304 onmousedown Window::Onmousedown DontDelete 00305 onmousemove Window::Onmousemove DontDelete 00306 onmouseout Window::Onmouseout DontDelete 00307 onmouseover Window::Onmouseover DontDelete 00308 onmouseup Window::Onmouseup DontDelete 00309 onmove Window::Onmove DontDelete 00310 onreset Window::Onreset DontDelete 00311 onresize Window::Onresize DontDelete 00312 onselect Window::Onselect DontDelete 00313 onsubmit Window::Onsubmit DontDelete 00314 onunload Window::Onunload DontDelete 00315 @end 00316 */ 00317 IMPLEMENT_PROTOFUNC_DOM(WindowFunc) 00318 00319 Window::Window(KHTMLPart *p) 00320 : ObjectImp(/*no proto*/), m_part(p), screen(0), history(0), external(0), m_frames(0), loc(0), m_evt(0) 00321 { 00322 winq = new WindowQObject(this); 00323 //kdDebug(6070) << "Window::Window this=" << this << " part=" << m_part << " " << m_part->name() << endl; 00324 } 00325 00326 Window::~Window() 00327 { 00328 delete winq; 00329 } 00330 00331 Window *Window::retrieveWindow(KHTMLPart *p) 00332 { 00333 Object obj = Object::dynamicCast( retrieve( p ) ); 00334 #ifndef NDEBUG 00335 // obj should never be null, except when javascript has been disabled in that part. 00336 if ( p && p->jScriptEnabled() ) 00337 { 00338 assert( !obj.isNull() ); 00339 #ifndef QWS 00340 assert( dynamic_cast<KJS::Window*>(obj.imp()) ); // type checking 00341 #endif 00342 } 00343 #endif 00344 if ( obj.isNull() ) // JS disabled 00345 return 0; 00346 return static_cast<KJS::Window*>(obj.imp()); 00347 } 00348 00349 Window *Window::retrieveActive(ExecState *exec) 00350 { 00351 ValueImp *imp = exec->interpreter()->globalObject().imp(); 00352 assert( imp ); 00353 #ifndef QWS 00354 assert( dynamic_cast<KJS::Window*>(imp) ); 00355 #endif 00356 return static_cast<KJS::Window*>(imp); 00357 } 00358 00359 Value Window::retrieve(KHTMLPart *p) 00360 { 00361 assert(p); 00362 KJSProxy *proxy = p->jScript(); 00363 if (proxy) { 00364 #ifdef KJS_VERBOSE 00365 kdDebug(6070) << "Window::retrieve part=" << p << " '" << p->name() << "' interpreter=" << proxy->interpreter() << " window=" << proxy->interpreter()->globalObject().imp() << endl; 00366 #endif 00367 return proxy->interpreter()->globalObject(); // the Global object is the "window" 00368 } else { 00369 #ifdef KJS_VERBOSE 00370 kdDebug(6070) << "Window::retrieve part=" << p << " '" << p->name() << "' no jsproxy." << endl; 00371 #endif 00372 return Undefined(); // This can happen with JS disabled on the domain of that window 00373 } 00374 } 00375 00376 Location *Window::location() const 00377 { 00378 if (!loc) 00379 const_cast<Window*>(this)->loc = new Location(m_part); 00380 return loc; 00381 } 00382 00383 ObjectImp* Window::frames( ExecState* exec ) const 00384 { 00385 return m_frames ? m_frames : 00386 (const_cast<Window*>(this)->m_frames = new FrameArray(exec,m_part)); 00387 } 00388 00389 // reference our special objects during garbage collection 00390 void Window::mark() 00391 { 00392 ObjectImp::mark(); 00393 if (screen && !screen->marked()) 00394 screen->mark(); 00395 if (history && !history->marked()) 00396 history->mark(); 00397 if (external && !external->marked()) 00398 external->mark(); 00399 if (m_frames && !m_frames->marked()) 00400 m_frames->mark(); 00401 //kdDebug(6070) << "Window::mark " << this << " marking loc=" << loc << endl; 00402 if (loc && !loc->marked()) 00403 loc->mark(); 00404 if (winq) 00405 winq->mark(); 00406 } 00407 00408 bool Window::hasProperty(ExecState *exec, const Identifier &p) const 00409 { 00410 // we don't want any operations on a closed window 00411 if (m_part.isNull()) 00412 return ( p == "closed" ); 00413 00414 if (ObjectImp::hasProperty(exec, p)) 00415 return true; 00416 00417 if (Lookup::findEntry(&WindowTable, p)) 00418 return true; 00419 00420 QString q = p.qstring(); 00421 if (m_part->findFrame(p.qstring())) 00422 return true; 00423 // allow window[1] or parent[1] etc. (#56983) 00424 bool ok; 00425 unsigned int i = p.toArrayIndex(&ok); 00426 if (ok) { 00427 QPtrList<KParts::ReadOnlyPart> frames = m_part->frames(); 00428 unsigned int len = frames.count(); 00429 if (i < len) 00430 return true; 00431 } 00432 00433 // allow shortcuts like 'Image1' instead of document.images.Image1 00434 if (m_part->document().isHTMLDocument()) { // might be XML 00435 DOM::HTMLDocument doc = m_part->htmlDocument(); 00436 // Keep in sync with tryGet 00437 NamedTagLengthDeterminer::TagLength tags[3] = { 00438 {ID_IMG, 0, 0L}, {ID_FORM, 0, 0L}, {ID_APPLET, 0, 0L} 00439 }; 00440 NamedTagLengthDeterminer(p.string(), tags, 3)(doc.handle()); 00441 for (int i = 0; i < 3; i++) 00442 if (tags[i].length > 0) 00443 return true; 00444 00445 return !doc.getElementById(p.string()).isNull(); 00446 } 00447 00448 return false; 00449 } 00450 00451 UString Window::toString(ExecState *) const 00452 { 00453 return "[object Window]"; 00454 } 00455 00456 Value Window::get(ExecState *exec, const Identifier &p) const 00457 { 00458 #ifdef KJS_VERBOSE 00459 kdDebug(6070) << "Window("<<this<<")::get " << p.qstring() << endl; 00460 #endif 00461 // we don't want any operations on a closed window 00462 if (m_part.isNull()) { 00463 if ( p == "closed" ) 00464 return Boolean( true ); 00465 return Undefined(); 00466 } 00467 00468 // Look for overrides first 00469 Value val = ObjectImp::get(exec, p); 00470 if (!val.isA(UndefinedType)) { 00471 //kdDebug(6070) << "Window::get found dynamic property '" << p.ascii() << "'" << endl; 00472 return isSafeScript(exec) ? val : Undefined(); 00473 } 00474 00475 const HashEntry* entry = Lookup::findEntry(&WindowTable, p); 00476 00477 // properties that work on all windows 00478 if (entry) { 00479 switch(entry->value) { 00480 case Closed: 00481 return Boolean( false ); 00482 case _Location: 00483 // No isSafeScript test here, we must be able to _set_ location.href (#49819) 00484 return Value(location()); 00485 case Frames: 00486 return Value(frames(exec)); 00487 case Opener: 00488 if (!m_part->opener()) 00489 return Null(); // ### a null Window might be better, but == null 00490 else // doesn't work yet 00491 return retrieve(m_part->opener()); 00492 case Parent: 00493 return retrieve(m_part->parentPart() ? m_part->parentPart() : (KHTMLPart*)m_part); 00494 case _Window: 00495 case Self: 00496 return retrieve(m_part); 00497 case Top: { 00498 KHTMLPart *p = m_part; 00499 while (p->parentPart()) 00500 p = p->parentPart(); 00501 return retrieve(p); 00502 } 00503 case Alert: 00504 case Confirm: 00505 case Prompt: 00506 case Open: 00507 case Focus: 00508 case Blur: 00509 return lookupOrCreateFunction<WindowFunc>(exec,p,this,entry->value,entry->params,entry->attr); 00510 default: 00511 break; 00512 } 00513 } 00514 00515 // properties that only work on safe windows 00516 if (isSafeScript(exec) && entry) 00517 { 00518 //kdDebug(6070) << "token: " << entry->value << endl; 00519 switch( entry->value ) { 00520 case Crypto: 00521 return Undefined(); // ### 00522 case DefaultStatus: 00523 return String(UString(m_part->jsDefaultStatusBarText())); 00524 case Status: 00525 return String(UString(m_part->jsStatusBarText())); 00526 case Document: 00527 if (m_part->document().isNull()) { 00528 kdDebug(6070) << "Document.write: adding <HTML><BODY> to create document" << endl; 00529 m_part->begin(); 00530 m_part->write("<HTML><BODY>"); 00531 m_part->end(); 00532 } 00533 return getDOMNode(exec,m_part->document()); 00534 case Node: 00535 return getNodeConstructor(exec); 00536 case Range: 00537 return getRangeConstructor(exec); 00538 case NodeFilter: 00539 return getNodeFilterConstructor(exec); 00540 case DOMException: 00541 return getDOMExceptionConstructor(exec); 00542 case CSSRule: 00543 return getCSSRuleConstructor(exec); 00544 case EventCtor: 00545 return getEventConstructor(exec); 00546 case _History: 00547 return Value(history ? history : 00548 (const_cast<Window*>(this)->history = new History(exec,m_part))); 00549 00550 case _External: 00551 return Value(external ? external : 00552 (const_cast<Window*>(this)->external = new External(exec,m_part))); 00553 00554 case Event: 00555 if (m_evt) 00556 return getDOMEvent(exec,*m_evt); 00557 else { 00558 #ifdef KJS_VERBOSE 00559 kdDebug(6070) << "WARNING: window(" << this << "," << m_part->name() << ").event, no event!" << endl; 00560 #endif 00561 return Undefined(); 00562 } 00563 case InnerHeight: 00564 if (!m_part->view()) 00565 return Undefined(); 00566 khtml::RenderWidget::flushWidgetResizes(); // make sure frames have their final size 00567 return Number(m_part->view()->visibleHeight()); 00568 case InnerWidth: 00569 if (!m_part->view()) 00570 return Undefined(); 00571 khtml::RenderWidget::flushWidgetResizes(); // make sure frames have their final size 00572 return Number(m_part->view()->visibleWidth()); 00573 case Length: 00574 return Number(m_part->frames().count()); 00575 case Name: 00576 return String(m_part->name()); 00577 case SideBar: 00578 return Value(new MozillaSidebarExtension(exec, m_part)); 00579 case _Navigator: 00580 case ClientInformation: { 00581 // Store the navigator in the object so we get the same one each time. 00582 Value nav( new Navigator(exec, m_part) ); 00583 const_cast<Window *>(this)->put(exec, "navigator", nav, DontDelete|ReadOnly|Internal); 00584 const_cast<Window *>(this)->put(exec, "clientInformation", nav, DontDelete|ReadOnly|Internal); 00585 return nav; 00586 } 00587 #ifdef Q_WS_QWS 00588 case _Konqueror: { 00589 Value k( new Konqueror(exec, m_part) ); 00590 const_cast<Window *>(this)->put(exec, "konqueror", k, DontDelete|ReadOnly|Internal); 00591 return k; 00592 } 00593 #endif 00594 case OffscreenBuffering: 00595 return Boolean(true); 00596 case OuterHeight: 00597 case OuterWidth: 00598 { 00599 if (!m_part->widget()) 00600 return Number(0); 00601 KWin::WindowInfo inf = KWin::windowInfo(m_part->widget()->topLevelWidget()->winId()); 00602 return Number(entry->value == OuterHeight ? 00603 inf.geometry().height() : inf.geometry().width()); 00604 } 00605 case PageXOffset: 00606 return Number(m_part->view()->contentsX()); 00607 case PageYOffset: 00608 return Number(m_part->view()->contentsY()); 00609 case Personalbar: 00610 return Undefined(); // ### 00611 case ScreenLeft: 00612 case ScreenX: { 00613 if (!m_part->view()) 00614 return Undefined(); 00615 QRect sg = KGlobalSettings::desktopGeometry(m_part->view()); 00616 return Number(m_part->view()->mapToGlobal(QPoint(0,0)).x() + sg.x()); 00617 } 00618 case ScreenTop: 00619 case ScreenY: { 00620 if (!m_part->view()) 00621 return Undefined(); 00622 QRect sg = KGlobalSettings::desktopGeometry(m_part->view()); 00623 return Number(m_part->view()->mapToGlobal(QPoint(0,0)).y() + sg.y()); 00624 } 00625 case ScrollX: { 00626 if (!m_part->view()) 00627 return Undefined(); 00628 return Number(m_part->view()->contentsX()); 00629 } 00630 case ScrollY: { 00631 if (!m_part->view()) 00632 return Undefined(); 00633 return Number(m_part->view()->contentsY()); 00634 } 00635 case Scrollbars: 00636 return Undefined(); // ### 00637 case _Screen: 00638 return Value(screen ? screen : 00639 (const_cast<Window*>(this)->screen = new Screen(exec))); 00640 case Image: 00641 return Value(new ImageConstructorImp(exec, m_part->document())); 00642 case Option: 00643 return Value(new OptionConstructorImp(exec, m_part->document())); 00644 case XMLHttpRequest: 00645 return Value(new XMLHttpRequestConstructorImp(exec, m_part->document())); 00646 case XMLSerializer: 00647 return Value(new XMLSerializerConstructorImp(exec)); 00648 case Close: 00649 case Scroll: // compatibility 00650 case ScrollBy: 00651 case ScrollTo: 00652 case MoveBy: 00653 case MoveTo: 00654 case ResizeBy: 00655 case ResizeTo: 00656 case CaptureEvents: 00657 case ReleaseEvents: 00658 case AddEventListener: 00659 case RemoveEventListener: 00660 case SetTimeout: 00661 case ClearTimeout: 00662 case SetInterval: 00663 case ClearInterval: 00664 case Print: 00665 return lookupOrCreateFunction<WindowFunc>(exec,p,this,entry->value,entry->params,entry->attr); 00666 // IE extension 00667 case Navigate: 00668 // Disabled in NS-compat mode. Supported by default - can't hurt, unless someone uses 00669 // if (navigate) to test for IE (unlikely). 00670 if ( exec->interpreter()->compatMode() == Interpreter::NetscapeCompat ) 00671 return Undefined(); 00672 return lookupOrCreateFunction<WindowFunc>(exec,p,this,entry->value,entry->params,entry->attr); 00673 case Onabort: 00674 return getListener(exec,DOM::EventImpl::ABORT_EVENT); 00675 case Onblur: 00676 return getListener(exec,DOM::EventImpl::BLUR_EVENT); 00677 case Onchange: 00678 return getListener(exec,DOM::EventImpl::CHANGE_EVENT); 00679 case Onclick: 00680 return getListener(exec,DOM::EventImpl::KHTML_ECMA_CLICK_EVENT); 00681 case Ondblclick: 00682 return getListener(exec,DOM::EventImpl::KHTML_ECMA_DBLCLICK_EVENT); 00683 case Ondragdrop: 00684 return getListener(exec,DOM::EventImpl::KHTML_DRAGDROP_EVENT); 00685 case Onerror: 00686 return getListener(exec,DOM::EventImpl::KHTML_ERROR_EVENT); 00687 case Onfocus: 00688 return getListener(exec,DOM::EventImpl::FOCUS_EVENT); 00689 case Onkeydown: 00690 return getListener(exec,DOM::EventImpl::KEYDOWN_EVENT); 00691 case Onkeypress: 00692 return getListener(exec,DOM::EventImpl::KHTML_KEYPRESS_EVENT); 00693 case Onkeyup: 00694 return getListener(exec,DOM::EventImpl::KEYUP_EVENT); 00695 case Onload: 00696 return getListener(exec,DOM::EventImpl::LOAD_EVENT); 00697 case Onmousedown: 00698 return getListener(exec,DOM::EventImpl::MOUSEDOWN_EVENT); 00699 case Onmousemove: 00700 return getListener(exec,DOM::EventImpl::MOUSEMOVE_EVENT); 00701 case Onmouseout: 00702 return getListener(exec,DOM::EventImpl::MOUSEOUT_EVENT); 00703 case Onmouseover: 00704 return getListener(exec,DOM::EventImpl::MOUSEOVER_EVENT); 00705 case Onmouseup: 00706 return getListener(exec,DOM::EventImpl::MOUSEUP_EVENT); 00707 case Onmove: 00708 return getListener(exec,DOM::EventImpl::KHTML_MOVE_EVENT); 00709 case Onreset: 00710 return getListener(exec,DOM::EventImpl::RESET_EVENT); 00711 case Onresize: 00712 return getListener(exec,DOM::EventImpl::RESIZE_EVENT); 00713 case Onselect: 00714 return getListener(exec,DOM::EventImpl::SELECT_EVENT); 00715 case Onsubmit: 00716 return getListener(exec,DOM::EventImpl::SUBMIT_EVENT); 00717 case Onunload: 00718 return getListener(exec,DOM::EventImpl::UNLOAD_EVENT); 00719 } 00720 } 00721 KHTMLPart *kp = m_part->findFrame( p.qstring() ); 00722 if (kp) 00723 return retrieve(kp); 00724 00725 // allow window[1] or parent[1] etc. (#56983) 00726 bool ok; 00727 unsigned int i = p.toArrayIndex(&ok); 00728 if (ok) { 00729 QPtrList<KParts::ReadOnlyPart> frames = m_part->frames(); 00730 unsigned int len = frames.count(); 00731 if (i < len) { 00732 KParts::ReadOnlyPart* frame = frames.at(i); 00733 if (frame && ::qt_cast<KHTMLPart*>(frame)) { 00734 KHTMLPart *khtml = static_cast<KHTMLPart*>(frame); 00735 return Window::retrieve(khtml); 00736 } 00737 } 00738 } 00739 00740 // allow shortcuts like 'Image1' instead of document.images.Image1 00741 if (isSafeScript(exec) && 00742 m_part->document().isHTMLDocument()) { // might be XML 00743 // This is only for images, forms and applets, see KJS::HTMLDocument::tryGet 00744 DOM::HTMLDocument doc = m_part->htmlDocument(); 00745 NamedTagLengthDeterminer::TagLength tags[3] = { 00746 {ID_IMG, 0, 0L}, {ID_FORM, 0, 0L}, {ID_APPLET, 0, 0L} 00747 }; 00748 NamedTagLengthDeterminer(p.string(), tags, 3)(doc.handle()); 00749 for (int i = 0; i < 3; i++) 00750 if (tags[i].length > 0) { 00751 if (tags[i].length == 1) 00752 return getDOMNode(exec, tags[i].last); 00753 // Get all the items with the same name 00754 return getDOMNodeList(exec, DOM::NodeList(new DOM::NamedTagNodeListImpl(doc.handle(), tags[i].id, p.string()))); 00755 } 00756 00757 DOM::Element element = doc.getElementById(p.string() ); 00758 if ( !element.isNull() ) 00759 return getDOMNode(exec, element ); 00760 } 00761 00762 // This isn't necessarily a bug. Some code uses if(!window.blah) window.blah=1 00763 // But it can also mean something isn't loaded or implemented, hence the WARNING to help grepping. 00764 #ifdef KJS_VERBOSE 00765 kdDebug(6070) << "WARNING: Window::get property not found: " << p.qstring() << endl; 00766 #endif 00767 return Undefined(); 00768 } 00769 00770 void Window::put(ExecState* exec, const Identifier &propertyName, const Value &value, int attr) 00771 { 00772 // Called by an internal KJS call (e.g. InterpreterImp's constructor) ? 00773 // If yes, save time and jump directly to ObjectImp. 00774 if ( (attr != None && attr != DontDelete) || 00775 // Same thing if we have a local override (e.g. "var location") 00776 ( isSafeScript( exec ) && ObjectImp::getDirect(propertyName) ) ) 00777 { 00778 ObjectImp::put( exec, propertyName, value, attr ); 00779 return; 00780 } 00781 00782 const HashEntry* entry = Lookup::findEntry(&WindowTable, propertyName); 00783 if (entry && !m_part.isNull()) 00784 { 00785 #ifdef KJS_VERBOSE 00786 kdDebug(6070) << "Window("<<this<<")::put " << propertyName.qstring() << endl; 00787 #endif 00788 switch( entry->value ) { 00789 case Status: { 00790 if (isSafeScript(exec) && m_part->settings()->windowStatusPolicy(m_part->url().host()) 00791 == KHTMLSettings::KJSWindowStatusAllow) { 00792 String s = value.toString(exec); 00793 m_part->setJSStatusBarText(s.value().qstring()); 00794 } 00795 return; 00796 } 00797 case DefaultStatus: { 00798 if (isSafeScript(exec) && m_part->settings()->windowStatusPolicy(m_part->url().host()) 00799 == KHTMLSettings::KJSWindowStatusAllow) { 00800 String s = value.toString(exec); 00801 m_part->setJSDefaultStatusBarText(s.value().qstring()); 00802 } 00803 return; 00804 } 00805 case _Location: 00806 goURL(exec, value.toString(exec).qstring(), false /*don't lock history*/); 00807 return; 00808 case Onabort: 00809 if (isSafeScript(exec)) 00810 setListener(exec, DOM::EventImpl::ABORT_EVENT,value); 00811 return; 00812 case Onblur: 00813 if (isSafeScript(exec)) 00814 setListener(exec, DOM::EventImpl::BLUR_EVENT,value); 00815 return; 00816 case Onchange: 00817 if (isSafeScript(exec)) 00818 setListener(exec, DOM::EventImpl::CHANGE_EVENT,value); 00819 return; 00820 case Onclick: 00821 if (isSafeScript(exec)) 00822 setListener(exec,DOM::EventImpl::KHTML_ECMA_CLICK_EVENT,value); 00823 return; 00824 case Ondblclick: 00825 if (isSafeScript(exec)) 00826 setListener(exec,DOM::EventImpl::KHTML_ECMA_DBLCLICK_EVENT,value); 00827 return; 00828 case Ondragdrop: 00829 if (isSafeScript(exec)) 00830 setListener(exec,DOM::EventImpl::KHTML_DRAGDROP_EVENT,value); 00831 return; 00832 case Onerror: 00833 if (isSafeScript(exec)) 00834 setListener(exec,DOM::EventImpl::KHTML_ERROR_EVENT,value); 00835 return; 00836 case Onfocus: 00837 if (isSafeScript(exec)) 00838 setListener(exec,DOM::EventImpl::FOCUS_EVENT,value); 00839 return; 00840 case Onkeydown: 00841 if (isSafeScript(exec)) 00842 setListener(exec,DOM::EventImpl::KEYDOWN_EVENT,value); 00843 return; 00844 case Onkeypress: 00845 if (isSafeScript(exec)) 00846 setListener(exec,DOM::EventImpl::KHTML_KEYPRESS_EVENT,value); 00847 return; 00848 case Onkeyup: 00849 if (isSafeScript(exec)) 00850 setListener(exec,DOM::EventImpl::KEYUP_EVENT,value); 00851 return; 00852 case Onload: 00853 if (isSafeScript(exec)) 00854 setListener(exec,DOM::EventImpl::LOAD_EVENT,value); 00855 return; 00856 case Onmousedown: 00857 if (isSafeScript(exec)) 00858 setListener(exec,DOM::EventImpl::MOUSEDOWN_EVENT,value); 00859 return; 00860 case Onmousemove: 00861 if (isSafeScript(exec)) 00862 setListener(exec,DOM::EventImpl::MOUSEMOVE_EVENT,value); 00863 return; 00864 case Onmouseout: 00865 if (isSafeScript(exec)) 00866 setListener(exec,DOM::EventImpl::MOUSEOUT_EVENT,value); 00867 return; 00868 case Onmouseover: 00869 if (isSafeScript(exec)) 00870 setListener(exec,DOM::EventImpl::MOUSEOVER_EVENT,value); 00871 return; 00872 case Onmouseup: 00873 if (isSafeScript(exec)) 00874 setListener(exec,DOM::EventImpl::MOUSEUP_EVENT,value); 00875 return; 00876 case Onmove: 00877 if (isSafeScript(exec)) 00878 setListener(exec,DOM::EventImpl::KHTML_MOVE_EVENT,value); 00879 return; 00880 case Onreset: 00881 if (isSafeScript(exec)) 00882 setListener(exec,DOM::EventImpl::RESET_EVENT,value); 00883 return; 00884 case Onresize: 00885 if (isSafeScript(exec)) 00886 setListener(exec,DOM::EventImpl::RESIZE_EVENT,value); 00887 return; 00888 case Onselect: 00889 if (isSafeScript(exec)) 00890 setListener(exec,DOM::EventImpl::SELECT_EVENT,value); 00891 return; 00892 case Onsubmit: 00893 if (isSafeScript(exec)) 00894 setListener(exec,DOM::EventImpl::SUBMIT_EVENT,value); 00895 return; 00896 case Onunload: 00897 if (isSafeScript(exec)) 00898 setListener(exec,DOM::EventImpl::UNLOAD_EVENT,value); 00899 return; 00900 case Name: 00901 if (isSafeScript(exec)) 00902 m_part->setName( value.toString(exec).qstring().local8Bit().data() ); 00903 return; 00904 default: 00905 break; 00906 } 00907 } 00908 if (isSafeScript(exec)) { 00909 //kdDebug(6070) << "Window("<<this<<")::put storing " << propertyName.qstring() << endl; 00910 ObjectImp::put(exec, propertyName, value, attr); 00911 } 00912 } 00913 00914 bool Window::toBoolean(ExecState *) const 00915 { 00916 return !m_part.isNull(); 00917 } 00918 00919 void Window::scheduleClose() 00920 { 00921 kdDebug(6070) << "Window::scheduleClose window.close() " << m_part << endl; 00922 Q_ASSERT(winq); 00923 QTimer::singleShot( 0, winq, SLOT( timeoutClose() ) ); 00924 } 00925 00926 void Window::closeNow() 00927 { 00928 if (!m_part.isNull()) 00929 { 00930 //kdDebug(6070) << k_funcinfo << " -> closing window" << endl; 00931 // We want to make sure that window.open won't find this part by name. 00932 m_part->setName( 0 ); 00933 m_part->deleteLater(); 00934 m_part = 0; 00935 } else 00936 kdDebug(6070) << k_funcinfo << "part is deleted already" << endl; 00937 } 00938 00939 void Window::afterScriptExecution() 00940 { 00941 DOM::DocumentImpl::updateDocumentsRendering(); 00942 QValueList<DelayedAction> delayedActions = m_delayed; 00943 m_delayed.clear(); 00944 QValueList<DelayedAction>::Iterator it = delayedActions.begin(); 00945 for ( ; it != delayedActions.end() ; ++it ) 00946 { 00947 switch ((*it).actionId) { 00948 case DelayedClose: 00949 scheduleClose(); 00950 return; // stop here, in case of multiple actions 00951 case DelayedGoHistory: 00952 goHistory( (*it).param.toInt() ); 00953 break; 00954 case NullAction: 00955 // FIXME: anything needs to be done here? This is warning anyways. 00956 break; 00957 }; 00958 } 00959 } 00960 00961 bool Window::checkIsSafeScript(KHTMLPart *activePart) const 00962 { 00963 if (m_part.isNull()) { // part deleted ? can't grant access 00964 kdDebug(6070) << "Window::isSafeScript: accessing deleted part !" << endl; 00965 return false; 00966 } 00967 if (!activePart) { 00968 kdDebug(6070) << "Window::isSafeScript: current interpreter's part is 0L!" << endl; 00969 return false; 00970 } 00971 if ( activePart == m_part ) // Not calling from another frame, no problem. 00972 return true; 00973 00974 if ( m_part->document().isNull() ) 00975 return true; // allow to access a window that was just created (e.g. with window.open("about:blank")) 00976 00977 DOM::HTMLDocument thisDocument = m_part->htmlDocument(); 00978 if ( thisDocument.isNull() ) { 00979 kdDebug(6070) << "Window::isSafeScript: trying to access an XML document !?" << endl; 00980 return false; 00981 } 00982 00983 DOM::HTMLDocument actDocument = activePart->htmlDocument(); 00984 if ( actDocument.isNull() ) { 00985 kdDebug(6070) << "Window::isSafeScript: active part has no document!" << endl; 00986 return false; 00987 } 00988 DOM::DOMString actDomain = actDocument.domain(); 00989 DOM::DOMString thisDomain = thisDocument.domain(); 00990 00991 if ( actDomain == thisDomain ) { 00992 #ifdef KJS_VERBOSE 00993 kdDebug(6070) << "JavaScript: access granted, domain is '" << actDomain.string() << "'" << endl; 00994 #endif 00995 return true; 00996 } 00997 00998 kdDebug(6070) << "WARNING: JavaScript: access denied for current frame '" << actDomain.string() << "' to frame '" << thisDomain.string() << "'" << endl; 00999 // TODO after 3.1: throw security exception (exec->setException()) 01000 return false; 01001 } 01002 01003 void Window::setListener(ExecState *exec, int eventId, Value func) 01004 { 01005 if (!isSafeScript(exec)) 01006 return; 01007 DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl*>(m_part->htmlDocument().handle()); 01008 if (!doc) 01009 return; 01010 01011 doc->setWindowEventListener(eventId,getJSEventListener(func,true)); 01012 } 01013 01014 Value Window::getListener(ExecState *exec, int eventId) const 01015 { 01016 if (!isSafeScript(exec)) 01017 return Undefined(); 01018 DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl*>(m_part->htmlDocument().handle()); 01019 if (!doc) 01020 return Undefined(); 01021 01022 DOM::EventListener *listener = doc->getWindowEventListener(eventId); 01023 if (listener) 01024 return static_cast<JSEventListener*>(listener)->listenerObj(); 01025 else 01026 return Null(); 01027 } 01028 01029 01030 JSEventListener *Window::getJSEventListener(const Value& val, bool html) 01031 { 01032 // This function is so hot that it's worth coding it directly with imps. 01033 if (val.type() != ObjectType) 01034 return 0; 01035 01036 // It's ObjectType, so it must be valid. 01037 Object listenerObject = Object::dynamicCast(val); 01038 ObjectImp *listenerObjectImp = listenerObject.imp(); 01039 01040 // 'listener' is not a simple ecma function. (Always use sanity checks: Better safe than sorry!) 01041 if (!listenerObject.implementsCall() && m_part && m_part->jScript() && m_part->jScript()->interpreter()) 01042 { 01043 Interpreter *interpreter = m_part->jScript()->interpreter(); 01044 01045 // 'listener' probably is an EventListener object containing a 'handleEvent' function. 01046 Value handleEventValue = listenerObject.get(interpreter->globalExec(), Identifier("handleEvent")); 01047 Object handleEventObject = Object::dynamicCast(handleEventValue); 01048 01049 if(handleEventObject.isValid() && handleEventObject.implementsCall()) 01050 { 01051 listenerObject = handleEventObject; 01052 listenerObjectImp = handleEventObject.imp(); 01053 } 01054 } 01055 01056 JSEventListener *existingListener = jsEventListeners[listenerObjectImp]; 01057 if (existingListener) 01058 return existingListener; 01059 01060 // Note that the JSEventListener constructor adds it to our jsEventListeners list 01061 return new JSEventListener(listenerObject, listenerObjectImp, Object(this), html); 01062 } 01063 01064 JSLazyEventListener *Window::getJSLazyEventListener(const QString& code, const QString& name, bool html) 01065 { 01066 return new JSLazyEventListener(code, name, Object(this), html); 01067 } 01068 01069 void Window::clear( ExecState *exec ) 01070 { 01071 delete winq; 01072 winq = 0L; 01073 // Get rid of everything, those user vars could hold references to DOM nodes 01074 deleteAllProperties( exec ); 01075 01076 // Break the dependency between the listeners and their object 01077 QPtrDictIterator<JSEventListener> it(jsEventListeners); 01078 for (; it.current(); ++it) 01079 it.current()->clear(); 01080 // Forget about the listeners (the DOM::NodeImpls will delete them) 01081 jsEventListeners.clear(); 01082 01083 if (!m_part.isNull()) { 01084 KJSProxy* proxy = m_part->jScript(); 01085 if (proxy) // i.e. JS not disabled 01086 { 01087 winq = new WindowQObject(this); 01088 // Now recreate a working global object for the next URL that will use us 01089 KJS::Interpreter *interpreter = proxy->interpreter(); 01090 interpreter->initGlobalObject(); 01091 } 01092 } 01093 } 01094 01095 void Window::setCurrentEvent( DOM::Event *evt ) 01096 { 01097 m_evt = evt; 01098 //kdDebug(6070) << "Window " << this << " (part=" << m_part << ")::setCurrentEvent m_evt=" << evt << endl; 01099 } 01100 01101 void Window::goURL(ExecState* exec, const QString& url, bool lockHistory) 01102 { 01103 Window* active = Window::retrieveActive(exec); 01104 // Complete the URL using the "active part" (running interpreter) 01105 if (active->part()) { 01106 if (url[0] == QChar('#')) { 01107 m_part->gotoAnchor(url.mid(1)); 01108 } else { 01109 QString dstUrl = active->part()->htmlDocument().completeURL(url).string(); 01110 KURL dst( dstUrl ); 01111 KURL partURL( m_part->url() ); 01112 // Remove refs for the comparison 01113 dst.setRef( QString::null ); 01114 partURL.setRef( QString::null ); 01115 kdDebug(6070) << "Window::goURL dstUrl=" << dst.prettyURL() << " partURL=" << partURL.prettyURL() 01116 << " identical: " << partURL.equals( dst, true ) << endl; 01117 01118 // check if we're allowed to inject javascript 01119 // SYNC check with khtml_part.cpp::slotRedirect! 01120 if ( isSafeScript(exec) || 01121 dstUrl.find(QString::fromLatin1("javascript:"), 0, false) != 0 ) 01122 m_part->scheduleRedirection(-1, 01123 dstUrl, 01124 lockHistory); 01125 } 01126 } 01127 } 01128 01129 void Window::delayedGoHistory( int steps ) 01130 { 01131 m_delayed.append( DelayedAction( DelayedGoHistory, steps ) ); 01132 } 01133 01134 void Window::goHistory( int steps ) 01135 { 01136 KParts::BrowserExtension *ext = m_part->browserExtension(); 01137 if(!ext) 01138 return; 01139 KParts::BrowserInterface *iface = ext->browserInterface(); 01140 01141 if ( !iface ) 01142 return; 01143 01144 iface->callMethod( "goHistory(int)", steps ); 01145 //emit ext->goHistory(steps); 01146 } 01147 01148 void KJS::Window::resizeTo(QWidget* tl, int width, int height) 01149 { 01150 KParts::BrowserExtension *ext = m_part->browserExtension(); 01151 if (!ext) { 01152 kdDebug(6070) << "Window::resizeTo found no browserExtension" << endl; 01153 return; 01154 } 01155 01156 // Security check: within desktop limits and bigger than 100x100 (per spec) 01157 if ( width < 100 || height < 100 ) { 01158 kdDebug(6070) << "Window::resizeTo refused, window would be too small ("<<width<<","<<height<<")" << endl; 01159 return; 01160 } 01161 01162 QRect sg = KGlobalSettings::desktopGeometry(tl); 01163 01164 if ( width > sg.width() || height > sg.height() ) { 01165 kdDebug(6070) << "Window::resizeTo refused, window would be too big ("<<width<<","<<height<<")" << endl; 01166 return; 01167 } 01168 01169 // Take into account the window frame - so that (width,height) is the external window size 01170 // ### (is that correct? for window.open it's the size of the HTML area...) 01171 int deltaWidth = tl->frameGeometry().width() - tl->width(); 01172 int deltaHeight = tl->frameGeometry().height() - tl->height(); 01173 01174 kdDebug() << "resizing to " << width - deltaWidth << "x" << height - deltaHeight << endl; 01175 01176 emit ext->resizeTopLevelWidget( width - deltaWidth, height - deltaHeight ); 01177 01178 // If the window is out of the desktop, move it up/left 01179 // (maybe we should use workarea instead of sg, otherwise the window ends up below kicker) 01180 int right = tl->x() + tl->frameGeometry().width(); 01181 int bottom = tl->y() + tl->frameGeometry().height(); 01182 int moveByX = 0; 01183 int moveByY = 0; 01184 if ( right > sg.right() ) 01185 moveByX = - right + sg.right(); // always <0 01186 if ( bottom > sg.bottom() ) 01187 moveByY = - bottom + sg.bottom(); // always <0 01188 if ( moveByX || moveByY ) 01189 emit ext->moveTopLevelWidget( tl->x() + moveByX , tl->y() + moveByY ); 01190 } 01191 01192 Value Window::openWindow(ExecState *exec, const List& args) 01193 { 01194 KHTMLView *widget = m_part->view(); 01195 Value v = args[0]; 01196 QString str = v.toString(exec).qstring(); 01197 01198 // prepare arguments 01199 KURL url; 01200 if (!str.isEmpty()) 01201 { 01202 KHTMLPart* p = Window::retrieveActive(exec)->m_part; 01203 if ( p ) 01204 url = p->htmlDocument().completeURL(str).string(); 01205 if ( !p || 01206 !static_cast<DOM::DocumentImpl*>(p->htmlDocument().handle())->isURLAllowed(url.url()) ) 01207 return Undefined(); 01208 } 01209 01210 KHTMLSettings::KJSWindowOpenPolicy policy = 01211 m_part->settings()->windowOpenPolicy(m_part->url().host()); 01212 if ( policy == KHTMLSettings::KJSWindowOpenAsk ) { 01213 if ( KMessageBox::questionYesNo(widget, 01214 str.isEmpty() ? 01215 i18n( "This site is requesting to open up a new browser " 01216 "window via JavaScript.\n" 01217 "Do you want to allow this?" ) : 01218 i18n( "<qt>This site is requesting to open<p>%1</p>in a new browser window via JavaScript.<br />" 01219 "Do you want to allow this?</qt>").arg(KStringHandler::csqueeze(url.htmlURL(), 100)), 01220 i18n( "Confirmation: JavaScript Popup" ) ) == KMessageBox::Yes ) 01221 policy = KHTMLSettings::KJSWindowOpenAllow; 01222 } else if ( policy == KHTMLSettings::KJSWindowOpenSmart ) 01223 { 01224 // window.open disabled unless from a key/mouse event 01225 if (static_cast<ScriptInterpreter *>(exec->interpreter())->isWindowOpenAllowed()) 01226 policy = KHTMLSettings::KJSWindowOpenAllow; 01227 } 01228 if ( policy != KHTMLSettings::KJSWindowOpenAllow ) { 01229 return Undefined(); 01230 } else { 01231 KParts::WindowArgs winargs; 01232 01233 // scan feature argument 01234 QString features; 01235 if (args.size()>2) { 01236 features = args[2].toString(exec).qstring(); 01237 // specifying window params means false defaults 01238 winargs.menuBarVisible = false; 01239 winargs.toolBarsVisible = false; 01240 winargs.statusBarVisible = false; 01241 QStringList flist = QStringList::split(',', features); 01242 QStringList::ConstIterator it = flist.begin(); 01243 while (it != flist.end()) { 01244 QString s = *it++; 01245 QString key, val; 01246 int pos = s.find('='); 01247 if (pos >= 0) { 01248 key = s.left(pos).stripWhiteSpace().lower(); 01249 val = s.mid(pos + 1).stripWhiteSpace().lower(); 01250 QRect screen = KGlobalSettings::desktopGeometry(widget->topLevelWidget()); 01251 01252 if (key == "left" || key == "screenx") { 01253 winargs.x = (int)val.toFloat() + screen.x(); 01254 if (winargs.x < screen.x() || winargs.x > screen.right()) 01255 winargs.x = screen.x(); // only safe choice until size is determined 01256 } else if (key == "top" || key == "screeny") { 01257 winargs.y = (int)val.toFloat() + screen.y(); 01258 if (winargs.y < screen.y() || winargs.y > screen.bottom()) 01259 winargs.y = screen.y(); // only safe choice until size is determined 01260 } else if (key == "height") { 01261 winargs.height = (int)val.toFloat() + 2*qApp->style().pixelMetric( QStyle::PM_DefaultFrameWidth ) + 2; 01262 if (winargs.height > screen.height()) // should actually check workspace 01263 winargs.height = screen.height(); 01264 if (winargs.height < 100) 01265 winargs.height = 100; 01266 } else if (key == "width") { 01267 winargs.width = (int)val.toFloat() + 2*qApp->style().pixelMetric( QStyle::PM_DefaultFrameWidth ) + 2; 01268 if (winargs.width > screen.width()) // should actually check workspace 01269 winargs.width = screen.width(); 01270 if (winargs.width < 100) 01271 winargs.width = 100; 01272 } else { 01273 goto boolargs; 01274 } 01275 continue; 01276 } else { 01277 // leaving away the value gives true 01278 key = s.stripWhiteSpace().lower(); 01279 val = "1"; 01280 } 01281 boolargs: 01282 if (key == "menubar") 01283 winargs.menuBarVisible = (val == "1" || val == "yes"); 01284 else if (key == "toolbar") 01285 winargs.toolBarsVisible = (val == "1" || val == "yes"); 01286 else if (key == "location") // ### missing in WindowArgs 01287 winargs.toolBarsVisible = (val == "1" || val == "yes"); 01288 else if (key == "status" || key == "statusbar") 01289 winargs.statusBarVisible = (val == "1" || val == "yes"); 01290 else if (key == "resizable") 01291 winargs.resizable = (val == "1" || val == "yes"); 01292 else if (key == "fullscreen") 01293 winargs.fullscreen = (val == "1" || val == "yes"); 01294 } 01295 } 01296 01297 KParts::URLArgs uargs; 01298 KHTMLPart *p = m_part; 01299 uargs.frameName = args.size() > 1 ? 01300 args[1].toString(exec).qstring() 01301 : QString("_blank"); 01302 if ( uargs.frameName.lower() == "_top" ) 01303 { 01304 while ( p->parentPart() ) 01305 p = p->parentPart(); 01306 Window::retrieveWindow(p)->goURL(exec, url.url(), false /*don't lock history*/); 01307 return Window::retrieve(p); 01308 } 01309 if ( uargs.frameName.lower() == "_parent" ) 01310 { 01311 if ( p->parentPart() ) 01312 p = p->parentPart(); 01313 Window::retrieveWindow(p)->goURL(exec, url.url(), false /*don't lock history*/); 01314 return Window::retrieve(p); 01315 } 01316 if ( uargs.frameName.lower() == "_self") 01317 { 01318 Window::retrieveWindow(p)->goURL(exec, url.url(), false /*don't lock history*/); 01319 return Window::retrieve(p); 01320 } 01321 if ( uargs.frameName.lower() == "replace" ) 01322 { 01323 Window::retrieveWindow(p)->goURL(exec, url.url(), true /*lock history*/); 01324 return Window::retrieve(p); 01325 } 01326 uargs.serviceType = "text/html"; 01327 01328 // request window (new or existing if framename is set) 01329 KParts::ReadOnlyPart *newPart = 0L; 01330 emit p->browserExtension()->createNewWindow(KURL(), uargs,winargs,newPart); 01331 if (newPart && ::qt_cast<KHTMLPart*>(newPart)) { 01332 KHTMLPart *khtmlpart = static_cast<KHTMLPart*>(newPart); 01333 //qDebug("opener set to %p (this Window's part) in new Window %p (this Window=%p)",part,win,window); 01334 khtmlpart->setOpener(p); 01335 khtmlpart->setOpenedByJS(true); 01336 if (khtmlpart->document().isNull()) { 01337 khtmlpart->begin(); 01338 khtmlpart->write("<HTML><BODY>"); 01339 khtmlpart->end(); 01340 if ( p->docImpl() ) { 01341 //kdDebug(6070) << "Setting domain to " << p->docImpl()->domain().string() << endl; 01342 khtmlpart->docImpl()->setDomain( p->docImpl()->domain()); 01343 khtmlpart->docImpl()->setBaseURL( p->docImpl()->baseURL() ); 01344 } 01345 } 01346 uargs.serviceType = QString::null; 01347 if (uargs.frameName.lower() == "_blank") 01348 uargs.frameName = QString::null; 01349 if (!url.isEmpty()) 01350 emit khtmlpart->browserExtension()->openURLRequest(url,uargs); 01351 return Window::retrieve(khtmlpart); // global object 01352 } else 01353 return Undefined(); 01354 } 01355 } 01356 01357 Value WindowFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) 01358 { 01359 KJS_CHECK_THIS( Window, thisObj ); 01360 Window *window = static_cast<Window *>(thisObj.imp()); 01361 QString str, str2; 01362 01363 KHTMLPart *part = window->m_part; 01364 if (!part) 01365 return Undefined(); 01366 01367 KHTMLView *widget = part->view(); 01368 Value v = args[0]; 01369 UString s = v.toString(exec); 01370 str = s.qstring(); 01371 01372 // functions that work everywhere 01373 switch(id) { 01374 case Window::Alert: 01375 if (!widget->dialogsAllowed()) 01376 return Undefined(); 01377 if ( part && part->xmlDocImpl() ) 01378 part->xmlDocImpl()->updateRendering(); 01379 KMessageBox::error(widget, QStyleSheet::convertFromPlainText(str), "JavaScript"); 01380 return Undefined(); 01381 case Window::Confirm: 01382 if (!widget->dialogsAllowed()) 01383 return Undefined(); 01384 if ( part && part->xmlDocImpl() ) 01385 part->xmlDocImpl()->updateRendering(); 01386 return Boolean((KMessageBox::warningYesNo(widget, QStyleSheet::convertFromPlainText(str), "JavaScript", 01387 KStdGuiItem::ok(), KStdGuiItem::cancel()) == KMessageBox::Yes)); 01388 case Window::Prompt: 01389 if (!widget->dialogsAllowed()) 01390 return Undefined(); 01391 if ( part && part->xmlDocImpl() ) 01392 part->xmlDocImpl()->updateRendering(); 01393 bool ok; 01394 if (args.size() >= 2) 01395 str2 = KInputDialog::getText(i18n("Prompt"), 01396 QStyleSheet::convertFromPlainText(str), 01397 args[1].toString(exec).qstring(), &ok, widget); 01398 else 01399 str2 = KInputDialog::getText(i18n("Prompt"), 01400 QStyleSheet::convertFromPlainText(str), 01401 QString::null, &ok, widget); 01402 if ( ok ) 01403 return String(str2); 01404 else 01405 return Null(); 01406 case Window::Open: 01407 return window->openWindow(exec, args); 01408 case Window::Navigate: 01409 window->goURL(exec, args[0].toString(exec).qstring(), false /*don't lock history*/); 01410 return Undefined(); 01411 case Window::Focus: { 01412 KHTMLSettings::KJSWindowFocusPolicy policy = 01413 part->settings()->windowFocusPolicy(part->url().host()); 01414 if(policy == KHTMLSettings::KJSWindowFocusAllow && widget) { 01415 widget->topLevelWidget()->raise(); 01416 widget->setActiveWindow(); 01417 } 01418 return Undefined(); 01419 } 01420 case Window::Blur: 01421 // TODO 01422 return Undefined(); 01423 }; 01424 01425 01426 // now unsafe functions.. 01427 if (!window->isSafeScript(exec)) 01428 return Undefined(); 01429 01430 switch (id) { 01431 case Window::ScrollBy: 01432 if(args.size() == 2 && widget) 01433 widget->scrollBy(args[0].toInt32(exec), args[1].toInt32(exec)); 01434 return Undefined(); 01435 case Window::Scroll: 01436 case Window::ScrollTo: 01437 if(args.size() == 2 && widget) 01438 widget->setContentsPos(args[0].toInt32(exec), args[1].toInt32(exec)); 01439 return Undefined(); 01440 case Window::MoveBy: { 01441 KHTMLSettings::KJSWindowMovePolicy policy = 01442 part->settings()->windowMovePolicy(part->url().host()); 01443 if(policy == KHTMLSettings::KJSWindowMoveAllow && args.size() == 2 && widget) 01444 { 01445 KParts::BrowserExtension *ext = part->browserExtension(); 01446 if (ext) { 01447 QWidget * tl = widget->topLevelWidget(); 01448 QRect sg = KGlobalSettings::desktopGeometry(tl); 01449 01450 QPoint dest = tl->pos() + QPoint( args[0].toInt32(exec), args[1].toInt32(exec) ); 01451 // Security check (the spec talks about UniversalBrowserWrite to disable this check...) 01452 if ( dest.x() >= sg.x() && dest.y() >= sg.x() && 01453 dest.x()+tl->width() <= sg.width()+sg.x() && 01454 dest.y()+tl->height() <= sg.height()+sg.y() ) 01455 emit ext->moveTopLevelWidget( dest.x(), dest.y() ); 01456 } 01457 } 01458 return Undefined(); 01459 } 01460 case Window::MoveTo: { 01461 KHTMLSettings::KJSWindowMovePolicy policy = 01462 part->settings()->windowMovePolicy(part->url().host()); 01463 if(policy == KHTMLSettings::KJSWindowMoveAllow && args.size() == 2 && widget) 01464 { 01465 KParts::BrowserExtension *ext = part->browserExtension(); 01466 if (ext) { 01467 QWidget * tl = widget->topLevelWidget(); 01468 QRect sg = KGlobalSettings::desktopGeometry(tl); 01469 01470 QPoint dest( args[0].toInt32(exec)+sg.x(), args[1].toInt32(exec)+sg.y() ); 01471 // Security check (the spec talks about UniversalBrowserWrite to disable this check...) 01472 if ( dest.x() >= sg.x() && dest.y() >= sg.y() && 01473 dest.x()+tl->width() <= sg.width()+sg.x() && 01474 dest.y()+tl->height() <= sg.height()+sg.y() ) 01475 emit ext->moveTopLevelWidget( dest.x(), dest.y() ); 01476 } 01477 } 01478 return Undefined(); 01479 } 01480 case Window::ResizeBy: { 01481 KHTMLSettings::KJSWindowResizePolicy policy = 01482 part->settings()->windowResizePolicy(part->url().host()); 01483 if(policy == KHTMLSettings::KJSWindowResizeAllow 01484 && args.size() == 2 && widget) 01485 { 01486 QWidget * tl = widget->topLevelWidget(); 01487 QRect geom = tl->frameGeometry(); 01488 window->resizeTo( tl, 01489 geom.width() + args[0].toInt32(exec), 01490 geom.height() + args[1].toInt32(exec) ); 01491 } 01492 return Undefined(); 01493 } 01494 case Window::ResizeTo: { 01495 KHTMLSettings::KJSWindowResizePolicy policy = 01496 part->settings()->windowResizePolicy(part->url().host()); 01497 if(policy == KHTMLSettings::KJSWindowResizeAllow 01498 && args.size() == 2 && widget) 01499 { 01500 QWidget * tl = widget->topLevelWidget(); 01501 window->resizeTo( tl, args[0].toInt32(exec), args[1].toInt32(exec) ); 01502 } 01503 return Undefined(); 01504 } 01505 case Window::SetTimeout: 01506 case Window::SetInterval: { 01507 bool singleShot; 01508 int i; // timeout interval 01509 if (args.size() == 0) 01510 return Undefined(); 01511 if (args.size() > 1) { 01512 singleShot = (id == Window::SetTimeout); 01513 i = args[1].toInt32(exec); 01514 } else { 01515 // second parameter is missing. Emulate Mozilla behavior. 01516 singleShot = true; 01517 i = 4; 01518 } 01519 if (v.isA(StringType)) { 01520 int r = (const_cast<Window*>(window))->winq->installTimeout(Identifier(s), i, singleShot ); 01521 return Number(r); 01522 } 01523 else if (v.isA(ObjectType) && Object::dynamicCast(v).implementsCall()) { 01524 Object func = Object::dynamicCast(v); 01525 List funcArgs; 01526 ListIterator it = args.begin(); 01527 int argno = 0; 01528 while (it != args.end()) { 01529 Value arg = it++; 01530 if (argno++ >= 2) 01531 funcArgs.append(arg); 01532 } 01533 if (args.size() < 2) 01534 funcArgs.append(Number(i)); 01535 int r = (const_cast<Window*>(window))->winq->installTimeout(func, funcArgs, i, singleShot ); 01536 return Number(r); 01537 } 01538 else 01539 return Undefined(); 01540 } 01541 case Window::ClearTimeout: 01542 case Window::ClearInterval: 01543 (const_cast<Window*>(window))->winq->clearTimeout(v.toInt32(exec)); 01544 return Undefined(); 01545 case Window::Close: { 01546 /* From http://developer.netscape.com/docs/manuals/js/client/jsref/window.htm : 01547 The close method closes only windows opened by JavaScript using the open method. 01548 If you attempt to close any other window, a confirm is generated, which 01549 lets the user choose whether the window closes. 01550 This is a security feature to prevent "mail bombs" containing self.close(). 01551 However, if the window has only one document (the current one) in its 01552 session history, the close is allowed without any confirm. This is a 01553 special case for one-off windows that need to open other windows and 01554 then dispose of themselves. 01555 */ 01556 bool doClose = false; 01557 if (!part->openedByJS()) 01558 { 01559 // To conform to the SPEC, we only ask if the window 01560 // has more than one entry in the history (NS does that too). 01561 History history(exec,part); 01562 if ( history.get( exec, "length" ).toInt32(exec) <= 1 || 01563 KMessageBox::questionYesNo( window->part()->widget(), i18n("Close window?"), i18n("Confirmation Required") ) == KMessageBox::Yes ) 01564 doClose = true; 01565 } 01566 else 01567 doClose = true; 01568 01569 if (doClose) 01570 { 01571 // If this is the current window (the one the interpreter runs in), 01572 // then schedule a delayed close (so that the script terminates first). 01573 // But otherwise, close immediately. This fixes w=window.open("","name");w.close();window.open("name"); 01574 if ( Window::retrieveActive(exec) == window ) { 01575 if (widget) { 01576 // quit all dialogs of this view 01577 // this fixes 'setTimeout('self.close()',1000); alert("Hi");' crash 01578 widget->closeChildDialogs(); 01579 } 01580 //kdDebug() << "scheduling delayed close" << endl; 01581 // We'll close the window at the end of the script execution 01582 Window* w = const_cast<Window*>(window); 01583 w->m_delayed.append( Window::DelayedAction( Window::DelayedClose ) ); 01584 } else { 01585 //kdDebug() << "closing NOW" << endl; 01586 (const_cast<Window*>(window))->closeNow(); 01587 } 01588 } 01589 return Undefined(); 01590 } 01591 case Window::Print: 01592 if ( widget ) { 01593 // ### TODO emit onbeforeprint event 01594 widget->print(); 01595 // ### TODO emit onafterprint event 01596 } 01597 case Window::CaptureEvents: 01598 case Window::ReleaseEvents: 01599 // Do nothing for now. These are NS-specific legacy calls. 01600 break; 01601 case Window::AddEventListener: { 01602 JSEventListener *listener = Window::retrieveActive(exec)->getJSEventListener(args[1]); 01603 DOM::Document doc = part->document(); 01604 if (doc.isHTMLDocument()) { 01605 DOM::HTMLDocument htmlDoc = doc; 01606 htmlDoc.body().addEventListener(args[0].toString(exec).string(),listener,args[2].toBoolean(exec)); 01607 } 01608 else 01609 doc.addEventListener(args[0].toString(exec).string(),listener,args[2].toBoolean(exec)); 01610 return Undefined(); 01611 } 01612 case Window::RemoveEventListener: { 01613 JSEventListener *listener = Window::retrieveActive(exec)->getJSEventListener(args[1]); 01614 DOM::Document doc = part->document(); 01615 if (doc.isHTMLDocument()) { 01616 DOM::HTMLDocument htmlDoc = doc; 01617 htmlDoc.body().removeEventListener(args[0].toString(exec).string(),listener,args[2].toBoolean(exec)); 01618 } 01619 else 01620 doc.removeEventListener(args[0].toString(exec).string(),listener,args[2].toBoolean(exec)); 01621 return Undefined(); 01622 } 01623 break; 01624 } 01625 return Undefined(); 01626 } 01627 01629 01630 // KDE 4: Make those parameters const ... & 01631 ScheduledAction::ScheduledAction(Object _func, List _args, QTime _nextTime, int _interval, bool _singleShot, 01632 int _timerId) 01633 { 01634 //kdDebug(6070) << "ScheduledAction::ScheduledAction(isFunction) " << this << endl; 01635 func = static_cast<ObjectImp*>(_func.imp()); 01636 args = _args; 01637 isFunction = true; 01638 singleShot = _singleShot; 01639 nextTime = _nextTime; 01640 interval = _interval; 01641 executing = false; 01642 timerId = _timerId; 01643 } 01644 01645 // KDE 4: Make it const QString & 01646 ScheduledAction::ScheduledAction(QString _code, QTime _nextTime, int _interval, bool _singleShot, int _timerId) 01647 { 01648 //kdDebug(6070) << "ScheduledAction::ScheduledAction(!isFunction) " << this << endl; 01649 //func = 0; 01650 //args = 0; 01651 func = 0; 01652 code = _code; 01653 isFunction = false; 01654 singleShot = _singleShot; 01655 nextTime = _nextTime; 01656 interval = _interval; 01657 executing = false; 01658 timerId = _timerId; 01659 } 01660 01661 void ScheduledAction::execute(Window *window) 01662 { 01663 ScriptInterpreter *interpreter = static_cast<ScriptInterpreter *>(window->m_part->jScript()->interpreter()); 01664 01665 interpreter->setProcessingTimerCallback(true); 01666 01667 //kdDebug(6070) << "ScheduledAction::execute " << this << endl; 01668 if (isFunction) { 01669 if (func->implementsCall()) { 01670 // #### check this 01671 Q_ASSERT( window->m_part ); 01672 if ( window->m_part ) 01673 { 01674 KJS::Interpreter *interpreter = window->m_part->jScript()->interpreter(); 01675 ExecState *exec = interpreter->globalExec(); 01676 Q_ASSERT( window == interpreter->globalObject().imp() ); 01677 Object obj( window ); 01678 func->call(exec,obj,args); // note that call() creates its own execution state for the func call 01679 if (exec->hadException()) 01680 exec->clearException(); 01681 01682 // Update our document's rendering following the execution of the timeout callback. 01683 window->m_part->document().updateRendering(); 01684 } 01685 } 01686 } 01687 else { 01688 window->m_part->executeScript(DOM::Node(), code); 01689 } 01690 01691 interpreter->setProcessingTimerCallback(false); 01692 } 01693 01694 void ScheduledAction::mark() 01695 { 01696 if (func && !func->marked()) 01697 func->mark(); 01698 args.mark(); 01699 } 01700 01701 ScheduledAction::~ScheduledAction() 01702 { 01703 //kdDebug(6070) << "ScheduledAction::~ScheduledAction " << this << endl; 01704 } 01705 01707 01708 WindowQObject::WindowQObject(Window *w) 01709 : parent(w) 01710 { 01711 //kdDebug(6070) << "WindowQObject::WindowQObject " << this << endl; 01712 part = parent->m_part; 01713 if ( !part ) 01714 kdDebug(6070) << "WARNING: null part in " << k_funcinfo << endl; 01715 else 01716 connect( part, SIGNAL( destroyed() ), 01717 this, SLOT( parentDestroyed() ) ); 01718 pausedTime = 0; 01719 lastTimerId = 0; 01720 } 01721 01722 WindowQObject::~WindowQObject() 01723 { 01724 //kdDebug(6070) << "WindowQObject::~WindowQObject " << this << endl; 01725 parentDestroyed(); // reuse same code 01726 } 01727 01728 void WindowQObject::parentDestroyed() 01729 { 01730 killTimers(); 01731 01732 QPtrListIterator<ScheduledAction> it(scheduledActions); 01733 for (; it.current(); ++it) 01734 delete it.current(); 01735 scheduledActions.clear(); 01736 } 01737 01738 int WindowQObject::installTimeout(const Identifier &handler, int t, bool singleShot) 01739 { 01740 int id = ++lastTimerId; 01741 if (t < 10) t = 10; 01742 QTime nextTime = QTime::currentTime().addMSecs(-pausedTime).addMSecs(t); 01743 ScheduledAction *action = new ScheduledAction(handler.qstring(),nextTime,t,singleShot,id); 01744 scheduledActions.append(action); 01745 setNextTimer(); 01746 return id; 01747 } 01748 01749 int WindowQObject::installTimeout(const Value &func, List args, int t, bool singleShot) 01750 { 01751 Object objFunc = Object::dynamicCast( func ); 01752 if (!objFunc.isValid()) 01753 return 0; 01754 int id = ++lastTimerId; 01755 if (t < 10) t = 10; 01756 QTime nextTime = QTime::currentTime().addMSecs(-pausedTime).addMSecs(t); 01757 ScheduledAction *action = new ScheduledAction(objFunc,args,nextTime,t,singleShot,id); 01758 scheduledActions.append(action); 01759 setNextTimer(); 01760 return id; 01761 } 01762 01763 void WindowQObject::clearTimeout(int timerId) 01764 { 01765 QPtrListIterator<ScheduledAction> it(scheduledActions); 01766 for (; it.current(); ++it) { 01767 ScheduledAction *action = it.current(); 01768 if (action->timerId == timerId) { 01769 scheduledActions.removeRef(action); 01770 if (!action->executing) 01771 delete action; 01772 return; 01773 } 01774 } 01775 } 01776 01777 void WindowQObject::mark() 01778 { 01779 QPtrListIterator<ScheduledAction> it(scheduledActions); 01780 for (; it.current(); ++it) 01781 it.current()->mark(); 01782 } 01783 01784 void WindowQObject::timerEvent(QTimerEvent *) 01785 { 01786 killTimers(); 01787 01788 if (scheduledActions.isEmpty()) 01789 return; 01790 01791 QTime currentActual = QTime::currentTime(); 01792 QTime currentAdjusted = currentActual.addMSecs(-pausedTime); 01793 01794 // Work out which actions are to be executed. We take a separate copy of 01795 // this list since the main one may be modified during action execution 01796 QPtrList<ScheduledAction> toExecute; 01797 QPtrListIterator<ScheduledAction> it(scheduledActions); 01798 for (; it.current(); ++it) 01799 if (currentAdjusted >= it.current()->nextTime) 01800 toExecute.append(it.current()); 01801 01802 // ### verify that the window can't be closed (and action deleted) during execution 01803 it = QPtrListIterator<ScheduledAction>(toExecute); 01804 for (; it.current(); ++it) { 01805 ScheduledAction *action = it.current(); 01806 if (!scheduledActions.containsRef(action)) // removed by clearTimeout() 01807 continue; 01808 01809 action->executing = true; // prevent deletion in clearTimeout() 01810 01811 if (action->singleShot) 01812 scheduledActions.removeRef(action); 01813 if (!parent->part().isNull()) 01814 action->execute(parent); 01815 01816 action->executing = false; 01817 01818 if (!scheduledActions.containsRef(action)) 01819 delete action; 01820 else 01821 action->nextTime = action->nextTime.addMSecs(action->interval); 01822 } 01823 01824 pausedTime += currentActual.msecsTo(QTime::currentTime()); 01825 01826 // Work out when next event is to occur 01827 setNextTimer(); 01828 } 01829 01830 void WindowQObject::setNextTimer() 01831 { 01832 if (scheduledActions.isEmpty()) 01833 return; 01834 01835 QPtrListIterator<ScheduledAction> it(scheduledActions); 01836 QTime nextTime = it.current()->nextTime; 01837 for (++it; it.current(); ++it) 01838 if (nextTime > it.current()->nextTime) 01839 nextTime = it.current()->nextTime; 01840 01841 QTime nextTimeActual = nextTime.addMSecs(pausedTime); 01842 int nextInterval = QTime::currentTime().msecsTo(nextTimeActual); 01843 if (nextInterval < 0) 01844 nextInterval = 0; 01845 startTimer(nextInterval); 01846 } 01847 01848 void WindowQObject::timeoutClose() 01849 { 01850 parent->closeNow(); 01851 } 01852 01853 Value FrameArray::get(ExecState *exec, const Identifier &p) const 01854 { 01855 #ifdef KJS_VERBOSE 01856 kdDebug(6070) << "FrameArray::get " << p.qstring() << " part=" << (void*)part << endl; 01857 #endif 01858 if (part.isNull()) 01859 return Undefined(); 01860 01861 QPtrList<KParts::ReadOnlyPart> frames = part->frames(); 01862 unsigned int len = frames.count(); 01863 if (p == lengthPropertyName) 01864 return Number(len); 01865 else if (p== "location") // non-standard property, but works in NS and IE 01866 { 01867 Object obj = Object::dynamicCast( Window::retrieve( part ) ); 01868 if ( !obj.isNull() ) 01869 return obj.get( exec, "location" ); 01870 return Undefined(); 01871 } 01872 01873 // check for the name or number 01874 KParts::ReadOnlyPart *frame = part->findFrame(p.qstring()); 01875 if (!frame) { 01876 bool ok; 01877 unsigned int i = p.toArrayIndex(&ok); 01878 if (ok && i < len) 01879 frame = frames.at(i); 01880 } 01881 01882 // we are potentially fetching a reference to a another Window object here. 01883 // i.e. we may be accessing objects from another interpreter instance. 01884 // Therefore we have to be a bit careful with memory management. 01885 if (frame && ::qt_cast<KHTMLPart*>(frame)) { 01886 KHTMLPart *khtml = static_cast<KHTMLPart*>(frame); 01887 return Window::retrieve(khtml); 01888 } 01889 01890 return ObjectImp::get(exec, p); 01891 } 01892 01894 01895 const ClassInfo Location::info = { "Location", 0, &LocationTable, 0 }; 01896 /* 01897 @begin LocationTable 11 01898 hash Location::Hash DontDelete 01899 host Location::Host DontDelete 01900 hostname Location::Hostname DontDelete 01901 href Location::Href DontDelete 01902 pathname Location::Pathname DontDelete 01903 port Location::Port DontDelete 01904 protocol Location::Protocol DontDelete 01905 search Location::Search DontDelete 01906 [[==]] Location::EqualEqual DontDelete|ReadOnly 01907 assign Location::Assign DontDelete|Function 1 01908 toString Location::ToString DontDelete|Function 0 01909 replace Location::Replace DontDelete|Function 1 01910 reload Location::Reload DontDelete|Function 0 01911 @end 01912 */ 01913 IMPLEMENT_PROTOFUNC_DOM(LocationFunc) 01914 Location::Location(KHTMLPart *p) : m_part(p) 01915 { 01916 //kdDebug(6070) << "Location::Location " << this << " m_part=" << (void*)m_part << endl; 01917 } 01918 01919 Location::~Location() 01920 { 01921 //kdDebug(6070) << "Location::~Location " << this << " m_part=" << (void*)m_part << endl; 01922 } 01923 01924 Value Location::get(ExecState *exec, const Identifier &p) const 01925 { 01926 #ifdef KJS_VERBOSE 01927 kdDebug(6070) << "Location::get " << p.qstring() << " m_part=" << (void*)m_part << endl; 01928 #endif 01929 01930 if (m_part.isNull()) 01931 return Undefined(); 01932 01933 const HashEntry *entry = Lookup::findEntry(&LocationTable, p); 01934 01935 // properties that work on all Location objects 01936 if ( entry && entry->value == Replace ) 01937 return lookupOrCreateFunction<LocationFunc>(exec,p,this,entry->value,entry->params,entry->attr); 01938 01939 // XSS check 01940 const Window* window = Window::retrieveWindow( m_part ); 01941 if ( !window || !window->isSafeScript(exec) ) 01942 return Undefined(); 01943 01944 KURL url = m_part->url(); 01945 if (entry) 01946 switch (entry->value) { 01947 case Hash: 01948 return String( url.ref().isNull() ? QString("") : "#" + url.ref() ); 01949 case Host: { 01950 UString str = url.host(); 01951 if (url.port()) 01952 str += ":" + QString::number((int)url.port()); 01953 return String(str); 01954 // Note: this is the IE spec. The NS spec swaps the two, it says 01955 // "The hostname property is the concatenation of the host and port properties, separated by a colon." 01956 // Bleh. 01957 } 01958 case Hostname: 01959 return String( url.host() ); 01960 case Href: 01961 if (!url.hasPath()) 01962 return String( url.prettyURL()+"/" ); 01963 else 01964 return String( url.prettyURL() ); 01965 case Pathname: 01966 return String( url.path().isEmpty() ? QString("/") : url.path() ); 01967 case Port: 01968 return String( url.port() ? QString::number((int)url.port()) : QString::fromLatin1("") ); 01969 case Protocol: 01970 return String( url.protocol()+":" ); 01971 case Search: 01972 return String( url.query() ); 01973 case EqualEqual: // [[==]] 01974 return String(toString(exec)); 01975 case ToString: 01976 return lookupOrCreateFunction<LocationFunc>(exec,p,this,entry->value,entry->params,entry->attr); 01977 } 01978 // Look for overrides 01979 ValueImp * val = ObjectImp::getDirect(p); 01980 if (val) 01981 return Value(val); 01982 if (entry && (entry->attr & Function)) 01983 return lookupOrCreateFunction<LocationFunc>(exec,p,this,entry->value,entry->params,entry->attr); 01984 01985 return Undefined(); 01986 } 01987 01988 void Location::put(ExecState *exec, const Identifier &p, const Value &v, int attr) 01989 { 01990 #ifdef KJS_VERBOSE 01991 kdDebug(6070) << "Location::put " << p.qstring() << " m_part=" << (void*)m_part << endl; 01992 #endif 01993 if (m_part.isNull()) 01994 return; 01995 01996 // XSS check 01997 const Window* window = Window::retrieveWindow( m_part ); 01998 if ( !window || !window->isSafeScript(exec) ) 01999 return; 02000 02001 QString str = v.toString(exec).qstring(); 02002 KURL url = m_part->url(); 02003 const HashEntry *entry = Lookup::findEntry(&LocationTable, p); 02004 if (entry) 02005 switch (entry->value) { 02006 case Href: { 02007 KHTMLPart* p = Window::retrieveActive(exec)->part(); 02008 if ( p ) 02009 url = p->htmlDocument().completeURL( str ).string(); 02010 else 02011 url = str; 02012 break; 02013 } 02014 case Hash: 02015 // when the hash is already the same ignore it 02016 if (str == url.ref()) return; 02017 url.setRef(str); 02018 break; 02019 case Host: { 02020 QString host = str.left(str.find(":")); 02021 QString port = str.mid(str.find(":")+1); 02022 url.setHost(host); 02023 url.setPort(port.toUInt()); 02024 break; 02025 } 02026 case Hostname: 02027 url.setHost(str); 02028 break; 02029 case Pathname: 02030 url.setPath(str); 02031 break; 02032 case Port: 02033 url.setPort(str.toUInt()); 02034 break; 02035 case Protocol: 02036 url.setProtocol(str); 02037 break; 02038 case Search: 02039 url.setQuery(str); 02040 break; 02041 } 02042 else { 02043 ObjectImp::put(exec, p, v, attr); 02044 return; 02045 } 02046 02047 Window::retrieveWindow(m_part)->goURL(exec, url.url(), false /* don't lock history*/ ); 02048 } 02049 02050 Value Location::toPrimitive(ExecState *exec, Type) const 02051 { 02052 Window* window = Window::retrieveWindow( m_part ); 02053 if ( window && window->isSafeScript(exec) ) 02054 return String(toString(exec)); 02055 return Undefined(); 02056 } 02057 02058 UString Location::toString(ExecState *exec) const 02059 { 02060 Window* window = Window::retrieveWindow( m_part ); 02061 if ( window && window->isSafeScript(exec) ) 02062 { 02063 if (!m_part->url().hasPath()) 02064 return m_part->url().prettyURL()+"/"; 02065 else 02066 return m_part->url().prettyURL(); 02067 } 02068 return ""; 02069 } 02070 02071 Value LocationFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) 02072 { 02073 KJS_CHECK_THIS( Location, thisObj ); 02074 Location *location = static_cast<Location *>(thisObj.imp()); 02075 KHTMLPart *part = location->part(); 02076 02077 if (!part) return Undefined(); 02078 02079 Window* window = Window::retrieveWindow(part); 02080 02081 if ( !window->isSafeScript(exec) && id != Location::Replace) 02082 return Undefined(); 02083 02084 switch (id) { 02085 case Location::Assign: 02086 case Location::Replace: 02087 Window::retrieveWindow(part)->goURL(exec, args[0].toString(exec).qstring(), 02088 id == Location::Replace); 02089 break; 02090 case Location::Reload: 02091 part->scheduleRedirection(-1, part->url().url(), true/*lock history*/); 02092 break; 02093 case Location::ToString: 02094 return String(location->toString(exec)); 02095 } 02096 return Undefined(); 02097 } 02098 02100 02101 const ClassInfo External::info = { "External", 0, 0, 0 }; 02102 /* 02103 @begin ExternalTable 4 02104 addFavorite External::AddFavorite DontDelete|Function 1 02105 @end 02106 */ 02107 IMPLEMENT_PROTOFUNC_DOM(ExternalFunc) 02108 02109 Value External::get(ExecState *exec, const Identifier &p) const 02110 { 02111 return lookupGetFunction<ExternalFunc,ObjectImp>(exec,p,&ExternalTable,this); 02112 } 02113 02114 Value ExternalFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) 02115 { 02116 KJS_CHECK_THIS( External, thisObj ); 02117 External *external = static_cast<External *>(thisObj.imp()); 02118 02119 KHTMLPart *part = external->part; 02120 if (!part) 02121 return Undefined(); 02122 02123 KHTMLView *widget = part->view(); 02124 02125 switch (id) { 02126 case External::AddFavorite: 02127 { 02128 if (!widget->dialogsAllowed()) 02129 return Undefined(); 02130 part->xmlDocImpl()->updateRendering(); 02131 if (args.size() != 1 && args.size() != 2) 02132 return Undefined(); 02133 02134 QString url = args[0].toString(exec).qstring(); 02135 QString title; 02136 if (args.size() == 2) 02137 title = args[1].toString(exec).qstring(); 02138 02139 // AK - don't do anything yet, for the moment i 02140 // just wanted the base js handling code in cvs 02141 return Undefined(); 02142 02143 QString question; 02144 if ( title.isEmpty() ) 02145 question = i18n("Do you want a bookmark pointing to the location \"%1\" to be added to your collection?") 02146 .arg(url); 02147 else 02148 question = i18n("Do you want a bookmark pointing to the location \"%1\" titled \"%2\" to be added to your collection?") 02149 .arg(url).arg(title); 02150 02151 if (KMessageBox::warningYesNo( 02152 widget, question, 02153 i18n("JavaScript Attempted Bookmark Insert"), 02154 i18n("Insert"), i18n("Disallow")) == KMessageBox::Yes) 02155 { 02156 KBookmarkManager *mgr = KBookmarkManager::userBookmarksManager(); 02157 mgr->addBookmarkDialog(url,title); 02158 } 02159 break; 02160 } 02161 default: 02162 return Undefined(); 02163 } 02164 02165 return Undefined(); 02166 } 02167 02169 02170 const ClassInfo History::info = { "History", 0, 0, 0 }; 02171 /* 02172 @begin HistoryTable 4 02173 length History::Length DontDelete|ReadOnly 02174 back History::Back DontDelete|Function 0 02175 forward History::Forward DontDelete|Function 0 02176 go History::Go DontDelete|Function 1 02177 @end 02178 */ 02179 IMPLEMENT_PROTOFUNC_DOM(HistoryFunc) 02180 02181 Value History::get(ExecState *exec, const Identifier &p) const 02182 { 02183 return lookupGet<HistoryFunc,History,ObjectImp>(exec,p,&HistoryTable,this); 02184 } 02185 02186 Value History::getValueProperty(ExecState *, int token) const 02187 { 02188 // if previous or next is implemented, make sure its not a major 02189 // privacy leak (see i.e. http://security.greymagic.com/adv/gm005-op/) 02190 switch (token) { 02191 case Length: 02192 { 02193 KParts::BrowserExtension *ext = part->browserExtension(); 02194 if ( !ext ) 02195 return Number( 0 ); 02196 02197 KParts::BrowserInterface *iface = ext->browserInterface(); 02198 if ( !iface ) 02199 return Number( 0 ); 02200 02201 QVariant length = iface->property( "historyLength" ); 02202 02203 if ( length.type() != QVariant::UInt ) 02204 return Number( 0 ); 02205 02206 return Number( length.toUInt() ); 02207 } 02208 default: 02209 kdDebug(6070) << "WARNING: Unhandled token in History::getValueProperty : " << token << endl; 02210 return Undefined(); 02211 } 02212 } 02213 02214 Value HistoryFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) 02215 { 02216 KJS_CHECK_THIS( History, thisObj ); 02217 History *history = static_cast<History *>(thisObj.imp()); 02218 02219 Value v = args[0]; 02220 Number n; 02221 if(!v.isNull()) 02222 n = v.toInteger(exec); 02223 02224 int steps; 02225 switch (id) { 02226 case History::Back: 02227 steps = -1; 02228 break; 02229 case History::Forward: 02230 steps = 1; 02231 break; 02232 case History::Go: 02233 steps = n.intValue(); 02234 break; 02235 default: 02236 return Undefined(); 02237 } 02238 02239 // Special case for go(0) from a frame -> reload only the frame 02240 // go(i!=0) from a frame navigates into the history of the frame only, 02241 // in both IE and NS (but not in Mozilla).... we can't easily do that 02242 // in Konqueror... 02243 if (!steps) // add && history->part->parentPart() to get only frames, but doesn't matter 02244 { 02245 history->part->openURL( history->part->url() ); 02246 } else 02247 { 02248 // Delay it. 02249 // Testcase: history.back(); alert("hello"); 02250 Window* window = Window::retrieveWindow( history->part ); 02251 window->delayedGoHistory( steps ); 02252 } 02253 return Undefined(); 02254 } 02255 02257 02258 #ifdef Q_WS_QWS 02259 02260 const ClassInfo Konqueror::info = { "Konqueror", 0, 0, 0 }; 02261 02262 bool Konqueror::hasProperty(ExecState *exec, const Identifier &p) const 02263 { 02264 if ( p.qstring().startsWith( "goHistory" ) ) return false; 02265 02266 return true; 02267 } 02268 02269 Value Konqueror::get(ExecState *exec, const Identifier &p) const 02270 { 02271 if ( p == "goHistory" || part->url().protocol() != "http" || part->url().host() != "localhost" ) 02272 return Undefined(); 02273 02274 KParts::BrowserExtension *ext = part->browserExtension(); 02275 if ( ext ) { 02276 KParts::BrowserInterface *iface = ext->browserInterface(); 02277 if ( iface ) { 02278 QVariant prop = iface->property( p.qstring().latin1() ); 02279 02280 if ( prop.isValid() ) { 02281 switch( prop.type() ) { 02282 case QVariant::Int: 02283 return Number( prop.toInt() ); 02284 case QVariant::String: 02285 return String( prop.toString() ); 02286 default: 02287 break; 02288 } 02289 } 02290 } 02291 } 02292 02293 return Value( new KonquerorFunc(this, p.qstring().latin1() ) ); 02294 } 02295 02296 Value KonquerorFunc::tryCall(ExecState *exec, Object &, const List &args) 02297 { 02298 KParts::BrowserExtension *ext = konqueror->part->browserExtension(); 02299 02300 if(!ext) 02301 return Undefined(); 02302 02303 KParts::BrowserInterface *iface = ext->browserInterface(); 02304 02305 if ( !iface ) 02306 return Undefined(); 02307 02308 QCString n = m_name.data(); 02309 n += "()"; 02310 iface->callMethod( n.data(), QVariant() ); 02311 02312 return Undefined(); 02313 } 02314 02315 UString Konqueror::toString(ExecState *) const 02316 { 02317 return UString("[object Konqueror]"); 02318 } 02319 02320 #endif 02321 02322 02323 #include "kjs_window.moc"
KDE Logo
This file is part of the documentation for khtml Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Sep 29 09:44:56 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003