Bug 30282

Summary: Web Inspector: Add console only layout mode
Product: WebKit Reporter: Paul Bakaus <pbakaus>
Component: Web Inspector (Deprecated)Assignee: Joseph Pecoraro <joepeck>
Status: RESOLVED FIXED    
Severity: Normal CC: aroben, bweinstein, garbage, joepeck, pbakaus, pfeldman, rik, timothy
Priority: P2    
Version: 528+ (Nightly build)   
Hardware: All   
OS: All   
Attachments:
Description Flags
[PATCH] Extra Button (It is a Preference) to Toggle Full Console Mode
none
[PATCH] Console Panel
joepeck: commit-queue-
[PATCH] Console Panel (Improved)
timothy: review-, joepeck: commit-queue-
[PATCH] Console Panel (Improved)
joepeck: commit-queue-
[PATCH] Console Panel (Even Better)
joepeck: commit-queue-
[PATCH] Console Panel (Even Better)
joepeck: commit-queue-
[PATCH] Console Panel (Even Better)
timothy: review+, joepeck: commit-queue-
Console Panel Icon none

Description Paul Bakaus 2009-10-11 01:37:39 PDT
Due to Firebug's different layout, it is possible to collapse all other tabs but the console. For JavaScript engineers, the console is the most often used feature of the Web Inspector, and I'd like to propose to find a way to show it exclusively.

Why? It dramatically improves working with the Web Inspector on smaller screens (read: any resolution smaller than 1920x1080), since a lot of the vertical real screen estate is lost, and for many, opening the Inspector in a seperate window isn't a real solution because we'd like to have the console information sticky with the current website in one visual place.

I therefore propose to implement one or many of the following way to display the console independently:

1) Make Inspector and Console entirely independent layout wise, so each can be disabled and enabled within the Developer menu
2) Implement a "console only" button somewhere
3) Make the current console button a three-way toggler to either enable, disable or exclusively show the console

My personal vote goes to 1 and 3, but I'd be very hapyp (and many others too!) with any of the solutions.

Thanks!
Comment 1 Timothy Hatcher 2009-10-11 08:17:59 PDT
3 sounds good to me.
Comment 2 Brian Weinstein 2009-11-18 17:30:33 PST
How about a full screen button next to the "Clear Console" button?

[ Hide Console ] [ Clear Console ] [ Full Screen ]

That button wouldn't be present if the console wasn't open, but if it was, it would toggle between Full Screen and non Full Screen, and would remember the user's preference. This is option 2, the one you said you weren't as enthusiastic about, but it would have some of the elements of 3 (button placement, etc.).
Comment 3 Joseph Pecoraro 2009-11-18 22:26:18 PST
Created attachment 43488 [details]
[PATCH] Extra Button (It is a Preference) to Toggle Full Console Mode

I tried a few different approaches. For instance, this was the 3 way button approach:
http://screencast.com/t/NmNkNGFi

However, the approach taken in this patch is Brian's approach:
http://screencast.com/t/YmJjODg4MjAt

The patch covers most of the details. Points to consider:
- The Drawer is the container for the Console, and also for the currently inactive Changes View. Therefore this button is a part of the Drawer, not the Console. Maybe my terminology in this patch is inappropriate?
- Move this button? On IRC we mentioned possibly putting the Console filter int the console itself. That might be a good place to put this button.
- I did experiment with deselecting the panel in Full mode. The way I did it was deselect after the slide up animation, show before the slide down animation. In the end this didn't look very clean, so I removed that behavior for this patch.
Comment 4 Paul Bakaus 2009-11-19 01:03:25 PST
Out of both screencasts, I also like the one Brian proposed better, and I think it would work for most people. One additional idea that came to my mind was to simply add the "Full console" mode to the top (tab) bar, a a bit like in Firebug, to make it more prominent. Clicking on the Console tab would then activate the console in full mode, while on any other pane/tab, it would be half-width/normal.

Great work though, we're getting there!
Comment 5 Joseph Pecoraro 2009-11-19 06:51:35 PST
(In reply to comment #4)
> One additional idea that came to my mind was to
> simply add the "Full console" mode to the top (tab) bar, a a bit like in
> Firebug, to make it more prominent. Clicking on the Console tab would then
> activate the console in full mode, while on any other pane/tab, it would be
> half-width/normal.

Basically, make a new "Panel" button in the Toolbar.  I'm simply amazed that I never came up with this... since this is nearly exactly what it looks like I'm doing!  Timothy is the gatekeeper on new panels. As a plus it would make creating an icon a little easier ;)

Paul you might also be interested in some of Pavel's ideas on having tabs for snippet / multiline edits. His ideas are on bug 30553.
Comment 6 Paul Bakaus 2009-11-19 07:03:22 PST
(In reply to comment #5)
> (In reply to comment #4)
> > One additional idea that came to my mind was to
> > simply add the "Full console" mode to the top (tab) bar, a a bit like in
> > Firebug, to make it more prominent. Clicking on the Console tab would then
> > activate the console in full mode, while on any other pane/tab, it would be
> > half-width/normal.
> 
> Basically, make a new "Panel" button in the Toolbar.  I'm simply amazed that I
> never came up with this... since this is nearly exactly what it looks like I'm
> doing!  Timothy is the gatekeeper on new panels. As a plus it would make
> creating an icon a little easier ;)

Happens to me quite often too ;) Sometimes the easiest solutions are the hardest
to get a grasp on.. looking forward to hear what Timothy thinks!

> 
> Paul you might also be interested in some of Pavel's ideas on having tabs for
> snippet / multiline edits. His ideas are on bug 30553.

Cool, will have a look! I'm extremely interested in improving the Web Inspector with
whatever I can.
Comment 7 Timothy Hatcher 2009-11-19 07:43:04 PST
I am fine with a new toolbar icon, it is a good solution. Right now the toolbar having a selection panel confuses me.
Comment 8 Joseph Pecoraro 2009-11-19 14:52:01 PST
Created attachment 43527 [details]
[PATCH] Console Panel

This patch does not include the consoleIcon.png image, however it adds that image to the appropriate build files and assumes it exists. I'll just wait on an image from Timothy Hatcher. The patch itself can be reviewed.

Remaining Issues:
- Switching Panels should be broken into two steps so that animating the drawer to full size should not temporarily show a white background.
- Switching off and on the Console panel should cancel the closing animation (if one is running) and retrigger the opening animation.
Comment 9 Joseph Pecoraro 2009-11-19 15:06:39 PST
Ahh, I forgot the possibility of reopening to the Panel. (InspectorController specialNameForJSPanel and friends). I'll see if I can get that part done tonight.
Comment 10 Joseph Pecoraro 2009-11-19 19:51:03 PST
Created attachment 43543 [details]
[PATCH] Console Panel (Improved)

> - Switching off and on the Console panel should cancel the closing animation
> (if one is running) and retrigger the opening animation.

Done.

> Ahh, I forgot the possibility of reopening to the Panel. (InspectorController
> specialNameForJSPanel and friends). I'll see if I can get that part done
> tonight.

Done. This completely reverses http://trac.webkit.org/changeset/46175 because then the Console was not a "full panel", and now it is.
Comment 11 Timothy Hatcher 2009-11-19 21:00:11 PST
Comment on attachment 43543 [details]
[PATCH] Console Panel (Improved)


> +        WebInspector.Panel.prototype.show.call(this);

I like to put a blank line after these.

> +        WebInspector.drawer.triggerConsoleMode(true);

I don't think triggerConsoleMode is a good name. Maybe enterPanelMode and exitPanelMode?

> +        WebInspector.Panel.prototype.hide.call(this);

Add a blank line.

> +        if (this.previousConsoleState == WebInspector.Drawer.State.Hidden)

Use ===.


> -    var anchoredStatusBar = document.getElementById("anchored-status-bar-items");
> -    anchoredStatusBar.appendChild(this.toggleConsoleButton);

Where did this go?


> +    this.fullConsole = false;

This should be be something like "fullPanel" since this is Drawer.js, and should not have console mentions. Why not just use this.state?

> +            if (this.visible && WebInspector.currentPanel === WebInspector.panels.console)

Can this not check the current panel and just use this.fullPanel? I'd like to not add this dependancy and console reference if you can avoid it.

> +            height = parseInt(this.element.style.height, 10);

Isn't base 10 the default?


> +            WebInspector.cancelAnimation(this.currentAnimation);
> +            delete this._animating;

Should you delete this.currentAnimation too?

> +        this.fullConsole = fullConsole;
> +        if (fullConsole) {
> +            if (this.visible)
> +                this._transitionToFullConsole();
> +        } else {
> +            if (this.visible)
> +                this._transitionToVariableConsole();
> +        }
> +    },
> +
> +    _transitionToFullConsole: function()
> +    {
> +        if (this._animating)
> +            return;
> +
> +        this.savedHeight = this.element.offsetHeight;
> +
> +        var height = window.innerHeight - this.toolbarElement.offsetHeight;
> +        this._animateDrawerHeight(height, WebInspector.Drawer.State.Full);
> +    },
> +
> +    _transitionToVariableConsole: function()
> +    {
> +        if (this._animating)
> +            return;
> +
> +        // If this animation gets cancelled, we want the state of the drawer to be Variable,
> +        // so that the new animation can't do an immediate transition between Hidden/Full states.
> +        this.state = WebInspector.Drawer.State.Variable;
> +
> +        var height = this.savedHeight;
> +        this._animateDrawerHeight(height, WebInspector.Drawer.State.Variable);
> +    },

More console mentions, should be generic.


> +        function animationFinished()
> +        {
> +            delete this._animating;
> +            this.state = finalState;
> +        }

Delete this.currentAnimation too?

> +        WebInspector.animations[key] = setTimeout(WebInspector.animateStyle, slice, animations, duration, callback, complete + slice, key);

Why not just make the key be the timeout id?
Comment 12 Joseph Pecoraro 2009-11-19 21:13:20 PST
> > +        WebInspector.drawer.triggerConsoleMode(true);
> 
> I don't think triggerConsoleMode is a good name. Maybe enterPanelMode and
> exitPanelMode?

Sounds good.


> > -    var anchoredStatusBar = document.getElementById("anchored-status-bar-items");
> > -    anchoredStatusBar.appendChild(this.toggleConsoleButton);
> 
> Where did this go?

Buried in the ChangeLog => "removed unnecessary element reordering"

The toggleConsoleButton is already specified in inspector.html. This was taking the element, and just re-adding it onto the end of the anchoredStatusBar elements. Useless action since the order is how we want it in the html already.


> > +    this.fullConsole = false;
> 
> This should be be something like "fullPanel" since this is Drawer.js, and
> should not have console mentions. Why not just use this.state?

I can rename this. As for merging this with this.state, I can't wrap my head around it right now to know if that covers all the animation cases or not. I'll give it a shot.


> > +            if (this.visible && WebInspector.currentPanel === WebInspector.panels.console)
> 
> Can this not check the current panel and just use this.fullPanel? I'd like to
> not add this dependancy and console reference if you can avoid it.

Sure.


> > +            height = parseInt(this.element.style.height, 10);
> 
> Isn't base 10 the default?

It is the default. I've gotten into the habit of being explicit because parseInt("010") parses as octal. The 10 is not necessary here, I can remove it.


> > +            WebInspector.cancelAnimation(this.currentAnimation);
> > +            delete this._animating;
> 
> Should you delete this.currentAnimation too?

I would need to add delete this.currentAnimation to every single animationFinished (3) in Drawer.js. I can do that =)


> > +        WebInspector.animations[key] = setTimeout(WebInspector.animateStyle, slice, animations, duration, callback, complete + slice, key);
> 
> Why not just make the key be the timeout id?

The timeout id changes every time this function retriggers itself (animateStyle does a timeout on animateStyle). Thus I have 1 key for the WebInspector.animations hash table. That value stored in the table for that key will always be the timeout of the current iteration of the timeout for that animation. Does this make sense?
Comment 13 Joseph Pecoraro 2009-11-19 21:58:27 PST
Created attachment 43550 [details]
[PATCH] Console Panel (Improved)

Addressed all the points.

More Todo (future patches):
- Convert WebInspector.animateStyle to an Interval instead of Timeouts
Comment 14 Joseph Pecoraro 2009-11-19 21:59:15 PST
I also need to update the function names in the ChangeLog. =/
Comment 15 Joseph Pecoraro 2009-11-19 22:13:31 PST
Created attachment 43553 [details]
[PATCH] Console Panel (Even Better)

Updated ChangeLog and a few style issues.
Comment 16 Joseph Pecoraro 2009-11-19 23:29:25 PST
Created attachment 43558 [details]
[PATCH] Console Panel (Even Better)

> More Todo (future patches):
> - Convert WebInspector.animateStyle to an Interval instead of Timeouts

Done.

Notes:
I refactored animateStyle to use setInterval. Some interesting points: the original didn't actually use the "current" value anywhere. It determines the current, it assigns it to variables, but those variables are never used constructively, some not at all. I haven't looked into the history about this. I just removed all the extra computations.

Because the Diff looks ugly you can view the new algorithm in color here:
http://pastie.textmate.org/private/kuuuktkk7jbfiph6fmnpdg

Video of current behavior:
http://screencast.com/t/NzE5YzFjZ

Sorry about the spam.
Comment 17 Pavel Feldman 2009-11-19 23:56:34 PST
Comment on attachment 43558 [details]
[PATCH] Console Panel (Even Better)

> diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
> index bfb93cb..ee06d88 100644
> --- a/WebCore/ChangeLog
> +++ b/WebCore/ChangeLog
> @@ -1,5 +1,71 @@
>  2009-11-19  Joseph Pecoraro  <joepeck@webkit.org>
>  
> +        Reviewed by NOBODY (OOPS!).
> +
> +        Web Inspector: Add Console Only Layout Mode
> +        https://bugs.webkit.org/show_bug.cgi?id=30282
> +
> +        Adds a Console Panel, which allows for a Full size Console. This
> +        extends the Drawer to the size of a Panel. This also fixes previous
> +        resize issues with the Drawer.
> +
> +        * inspector/front-end/ConsolePanel.js: Added.
> +        (WebInspector.ConsolePanel):
> +        (WebInspector.ConsolePanel.prototype.toolbarItemClass.get toolbarItemLabel):
> +        (WebInspector.ConsolePanel.prototype.show):
> +        (WebInspector.ConsolePanel.prototype.hide):
> +        * inspector/front-end/Drawer.js:
> +        (WebInspector.Drawer):
> +        (WebInspector.Drawer.prototype.set visibleView):
> +        (WebInspector.Drawer.prototype.get savedHeight): save the height of the variable console.
> +        (WebInspector.Drawer.prototype.set savedHeight):
> +        (WebInspector.Drawer.prototype.show.animationFinished):
> +        (WebInspector.Drawer.prototype.show):
> +        (WebInspector.Drawer.prototype.hide.animationFinished):
> +        (WebInspector.Drawer.prototype.hide):
> +        (WebInspector.Drawer.prototype.resize): resize appropriately if full/non-full
> +        (WebInspector.Drawer.prototype.enterPanelMode):
> +        (WebInspector.Drawer.prototype.exitPanelMode):
> +        (WebInspector.Drawer.prototype._cancelAnimationIfNeeded):
> +        (WebInspector.Drawer.prototype._animateDrawerHeight.animationFinished):
> +        (WebInspector.Drawer.prototype._animateDrawerHeight):
> +        (WebInspector.Drawer.prototype._animationDuration):
> +        (WebInspector.Drawer.prototype._startStatusBarDragging):
> +        (WebInspector.Drawer.prototype._statusBarDragging):
> +        (WebInspector.Drawer.prototype._endStatusBarDragging):
> +
> +        Miscellaneous changes and cleanup.
> +
> +        * English.lproj/localizedStrings.js: "Console" toolbar title.
> +        * inspector/front-end/ConsoleView.js: removed unnecessary element reordering  
> +        * inspector/front-end/Images/consoleIcon.png: added.
> +        * inspector/front-end/inspector.css: added icon.
> +        * inspector/front-end/inspector.html:
> +        * inspector/front-end/inspector.js:
> +        (WebInspector._createPanels): create console panel
> +        (WebInspector.windowResize): resize drawer if necessary
> +        (WebInspector.documentKeyDown): esc should not toggle the console when in panel mode
> +        (WebInspector.animateStyle): start animation interval, returns the interval key
> +        (WebInspector.toggleAttach): resize drawer if necessary
> +        (WebInspector.showConsolePanel): restore the panel when the inspector restarts
> +        (WebInspector.showProfileForURL): style fix
> +
> +        Restore the panel when the inspector restarts.
> +
> +        * inspector/InspectorController.cpp:
> +        (WebCore::InspectorController::setWindowVisible):
> +        (WebCore::InspectorController::specialPanelForJSName):
> +        * inspector/InspectorFrontend.cpp:
> +        (WebCore::InspectorFrontend::showPanel):
> +
> +        Build files.
> +
> +        * WebCore.gypi:
> +        * WebCore.vcproj/WebCore.vcproj:
> +        * inspector/front-end/WebKit.qrc:
> +
> +2009-11-19  Joseph Pecoraro  <joepeck@webkit.org>
> +
>          Reviewed by Timothy Hatcher.
>  
>          Web Inspector: Resync Resources Backend and Frontend
> diff --git a/WebCore/English.lproj/localizedStrings.js b/WebCore/English.lproj/localizedStrings.js
> index b6b05c56e87a48826abb630a22222a3b278cd140..ef981c78d851631cc0bc895f52f6bc4bea4980a4 100644
> GIT binary patch
> delta 60
> zcmZp<!FcTk;|7+T$>%s!CSMR{(aK{eX2@sAVMt|AVu)o>V6X*ZB?f1p7_y8t0~Z4T
> D9sCW~
> 
> delta 9
> Qcmcb1gR$iX;|7)-02nR=EdT%j
> 
> diff --git a/WebCore/WebCore.gypi b/WebCore/WebCore.gypi
> index 8c51a60..6c49885 100644
> --- a/WebCore/WebCore.gypi
> +++ b/WebCore/WebCore.gypi
> @@ -3616,6 +3616,7 @@
>              'inspector/front-end/CallStackSidebarPane.js',
>              'inspector/front-end/ChangesView.js',
>              'inspector/front-end/Color.js',
> +            'inspector/front-end/ConsolePanel.js',
>              'inspector/front-end/ConsoleView.js',
>              'inspector/front-end/CookieItemsView.js',
>              'inspector/front-end/Database.js',
> @@ -3684,6 +3685,7 @@
>              'inspector/front-end/Images/clearConsoleButtonGlyph.png',
>              'inspector/front-end/Images/closeButtons.png',
>              'inspector/front-end/Images/consoleButtonGlyph.png',
> +            'inspector/front-end/Images/consoleIcon.png',
>              'inspector/front-end/Images/cookie.png',
>              'inspector/front-end/Images/database.png',
>              'inspector/front-end/Images/databaseTable.png',
> diff --git a/WebCore/WebCore.vcproj/WebCore.vcproj b/WebCore/WebCore.vcproj/WebCore.vcproj
> index 85c5f6e..591d350 100644
> --- a/WebCore/WebCore.vcproj/WebCore.vcproj
> +++ b/WebCore/WebCore.vcproj/WebCore.vcproj
> @@ -42282,6 +42282,9 @@
>  					>
>  				</File>
>  				<File
> +					RelativePath="..\inspector\front-end\ConsolePanel.js"
> +					>
> +				<File
>  					RelativePath="..\inspector\front-end\ConsoleView.js"
>  					>
>  				</File>
> diff --git a/WebCore/inspector/InspectorController.cpp b/WebCore/inspector/InspectorController.cpp
> index 920c3f0..52436ee 100644
> --- a/WebCore/inspector/InspectorController.cpp
> +++ b/WebCore/inspector/InspectorController.cpp
> @@ -315,10 +315,7 @@ void InspectorController::setWindowVisible(bool visible, bool attached)
>          setAttachedWindow(attached);
>          populateScriptObjects();
>  
> -        // Console panel is implemented as a 'fast view', so there should be
> -        // real panel opened along with it.
> -        bool showConsole = m_showAfterVisible == ConsolePanel;
> -        if (m_showAfterVisible == CurrentPanel || showConsole) {
> +        if (m_showAfterVisible == CurrentPanel) {
>            Setting lastActivePanelSetting = setting(lastActivePanelSettingName);
>            if (lastActivePanelSetting.type() == Setting::StringType)
>                m_showAfterVisible = specialPanelForJSName(lastActivePanelSetting.string());
> @@ -333,8 +330,6 @@ void InspectorController::setWindowVisible(bool visible, bool attached)
>              enableDebugger();
>  #endif
>          showPanel(m_showAfterVisible);
> -        if (showConsole)
> -            showPanel(ConsolePanel);
>      } else {
>  #if ENABLE(JAVASCRIPT_DEBUGGER)
>          // If the window is being closed with the debugger enabled,
> @@ -1811,6 +1806,8 @@ InspectorController::SpecialPanels InspectorController::specialPanelForJSName(co
>          return ProfilesPanel;
>      else if (panelName == "storage" || panelName == "databases")
>          return StoragePanel;
> +    else if (panelName == "console")
> +        return ConsolePanel;
>      else
>          return ElementsPanel;
>  }
> diff --git a/WebCore/inspector/InspectorFrontend.cpp b/WebCore/inspector/InspectorFrontend.cpp
> index 6942d02..6e02db1 100644
> --- a/WebCore/inspector/InspectorFrontend.cpp
> +++ b/WebCore/inspector/InspectorFrontend.cpp
> @@ -151,7 +151,7 @@ void InspectorFrontend::showPanel(int panel)
>      const char* showFunctionName;
>      switch (panel) {
>          case InspectorController::ConsolePanel:
> -            showFunctionName = "showConsole";
> +            showFunctionName = "showConsolePanel";
>              break;
>          case InspectorController::ElementsPanel:
>              showFunctionName = "showElementsPanel";
> diff --git a/WebCore/inspector/front-end/ConsolePanel.js b/WebCore/inspector/front-end/ConsolePanel.js
> new file mode 100644
> index 0000000..e0292c6
> --- /dev/null
> +++ b/WebCore/inspector/front-end/ConsolePanel.js
> @@ -0,0 +1,63 @@
> +/*
> + * Copyright (C) 2009 Joseph Pecoraro
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + *
> + * 1.  Redistributions of source code must retain the above copyright
> + *     notice, this list of conditions and the following disclaimer.
> + * 2.  Redistributions in binary form must reproduce the above copyright
> + *     notice, this list of conditions and the following disclaimer in the
> + *     documentation and/or other materials provided with the distribution.
> + * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
> + *     its contributors may be used to endorse or promote products derived
> + *     from this software without specific prior written permission.
> + *
> + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
> + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
> + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
> + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
> + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
> + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
> + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + */
> +
> +WebInspector.ConsolePanel = function()
> +{
> +    WebInspector.Panel.call(this);
> +}
> +
> +WebInspector.ConsolePanel.prototype = {
> +    toolbarItemClass: "console",
> +
> +    get toolbarItemLabel()
> +    {
> +        return WebInspector.UIString("Console");
> +    },
> +
> +    show: function()
> +    {
> +        WebInspector.Panel.prototype.show.call(this);
> +
> +        this.previousConsoleState = WebInspector.drawer.state;

This can be private (this._previousConsoleState)

> +        WebInspector.drawer.enterPanelMode();
> +        WebInspector.showConsole();
> +    },
> +
> +    hide: function()
> +    {
> +        WebInspector.Panel.prototype.hide.call(this);
> +
> +        if (this.previousConsoleState === WebInspector.Drawer.State.Hidden) {
> +            WebInspector.drawer.visible = false;
> +            WebInspector.drawer.fullPanel = false;

You have nice methods that encapsulate drawer behavior for enterPanelMode nad exitPanelMode. Should you introduce some reset method as well and hide visible and fullPanel?
> +        } else
> +            WebInspector.drawer.exitPanelMode();
> +    }
> +}
> +
> +WebInspector.ConsolePanel.prototype.__proto__ = WebInspector.Panel.prototype;
> diff --git a/WebCore/inspector/front-end/ConsoleView.js b/WebCore/inspector/front-end/ConsoleView.js
> index f03c647..9f006e3 100644
> --- a/WebCore/inspector/front-end/ConsoleView.js
> +++ b/WebCore/inspector/front-end/ConsoleView.js
> @@ -57,9 +57,6 @@ WebInspector.ConsoleView = function(drawer)
>      this.toggleConsoleButton.title = WebInspector.UIString("Show console.");
>      this.toggleConsoleButton.addEventListener("click", this._toggleConsoleButtonClicked.bind(this), false);
>  
> -    var anchoredStatusBar = document.getElementById("anchored-status-bar-items");
> -    anchoredStatusBar.appendChild(this.toggleConsoleButton);
> -    
>      // Will hold the list of filter elements
>      this.filterBarElement = document.getElementById("console-filter");
>      
> diff --git a/WebCore/inspector/front-end/Drawer.js b/WebCore/inspector/front-end/Drawer.js
> index 1b50f91..66770a1 100644
> --- a/WebCore/inspector/front-end/Drawer.js
> +++ b/WebCore/inspector/front-end/Drawer.js
> @@ -7,13 +7,13 @@
>   * are met:
>   *
>   * 1.  Redistributions of source code must retain the above copyright
> - *     notice, this list of conditions and the following disclaimer. 
> + *     notice, this list of conditions and the following disclaimer.
>   * 2.  Redistributions in binary form must reproduce the above copyright
>   *     notice, this list of conditions and the following disclaimer in the
> - *     documentation and/or other materials provided with the distribution. 
> + *     documentation and/or other materials provided with the distribution.
>   * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
>   *     its contributors may be used to endorse or promote products derived
> - *     from this software without specific prior written permission. 
> + *     from this software without specific prior written permission.
>   *
>   * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
>   * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
> @@ -31,6 +31,12 @@ WebInspector.Drawer = function()
>  {
>      WebInspector.View.call(this, document.getElementById("drawer"));
>  
> +    this.savedHeight = 0;
> +    this.state = WebInspector.Drawer.State.Hidden;
> +    this.fullPanel = false;
> +
> +    this.mainElement = document.getElementById("main");
> +    this.toolbarElement = document.getElementById("toolbar");

Same here - you do access some of the drawer properties from the outside. Would be nice to distinguish between public and private ones.

>      this.mainStatusBar = document.getElementById("main-status-bar");
>      this.mainStatusBar.addEventListener("mousedown", this._startStatusBarDragging.bind(this), true);
>      this.viewStatusBar = document.getElementById("other-drawer-status-bar-items");
> @@ -45,6 +51,8 @@ WebInspector.Drawer.prototype = {
>      set visibleView(x)
>      {
>          if (this._visibleView === x) {
> +            if (this.visible && this.fullPanel)
> +                return;
>              this.visible = !this.visible;
>              return;
>          }
> @@ -64,6 +72,17 @@ WebInspector.Drawer.prototype = {
>          }
>      },
>  
> +    get savedHeight()
> +    {
> +        var height = this._savedHeight || this.element.offsetHeight;
> +        return Number.constrain(height, Preferences.minConsoleHeight, window.innerHeight - this.mainElement.totalOffsetTop - Preferences.minConsoleHeight);
> +    },
> +
> +    set savedHeight(x)
> +    {
> +        this._savedHeight = x;
> +    },
> +

I don't think you need setter for this. I hope you mutate from within this class only, you should just assign to this._savedHeight.

>      showView: function(view)
>      {
>          if (!this.visible || this.visibleView !== view)
> @@ -85,15 +104,16 @@ WebInspector.Drawer.prototype = {
>          document.body.addStyleClass("drawer-visible");
>  
>          var anchoredItems = document.getElementById("anchored-status-bar-items");
> -
> +        var height = (this.fullPanel ? window.innerHeight - this.toolbarElement.offsetHeight : this.savedHeight);
>          var animations = [
> -            {element: document.getElementById("main"), end: {bottom: this.element.offsetHeight}},
> +            {element: this.element, end: {height: height}},
> +            {element: document.getElementById("main"), end: {bottom: height}},
>              {element: document.getElementById("main-status-bar"), start: {"padding-left": anchoredItems.offsetWidth - 1}, end: {"padding-left": 0}},
>              {element: document.getElementById("other-drawer-status-bar-items"), start: {opacity: 0}, end: {opacity: 1}}
>          ];
>  
> -        var consoleStatusBar = document.getElementById("drawer-status-bar");
> -        consoleStatusBar.insertBefore(anchoredItems, consoleStatusBar.firstChild);
> +        var drawerStatusBar = document.getElementById("drawer-status-bar");
> +        drawerStatusBar.insertBefore(anchoredItems, drawerStatusBar.firstChild);
>  
>          function animationFinished()
>          {
> @@ -102,9 +122,11 @@ WebInspector.Drawer.prototype = {
>              if (this.visibleView.afterShow)
>                  this.visibleView.afterShow();
>              delete this._animating;
> +            delete this.currentAnimationInterval;
> +            this.state = (this.fullPanel ? WebInspector.Drawer.State.Full : WebInspector.Drawer.State.Variable);
>          }
>  
> -        WebInspector.animateStyle(animations, window.event && window.event.shiftKey ? 2000 : 250, animationFinished.bind(this));
> +        this.currentAnimationInterval = WebInspector.animateStyle(animations, this._animationDuration(), animationFinished.bind(this));

Ditto

>      },
>  
>      hide: function()
> @@ -113,7 +135,7 @@ WebInspector.Drawer.prototype = {
>              return;
>  
>          WebInspector.View.prototype.hide.call(this);
> -        
> +
>          if (this.visibleView)
>              this.visibleView.hide();
>  
> @@ -124,9 +146,9 @@ WebInspector.Drawer.prototype = {
>  
>          var anchoredItems = document.getElementById("anchored-status-bar-items");
>  
> -        // Temporally set properties and classes to mimic the post-animation values so panels
> +        // Temporarily set properties and classes to mimic the post-animation values so panels
>          // like Elements in their updateStatusBarItems call will size things to fit the final location.
> -        document.getElementById("main-status-bar").style.setProperty("padding-left", (anchoredItems.offsetWidth - 1) + "px");
> +        this.mainStatusBar.style.setProperty("padding-left", (anchoredItems.offsetWidth - 1) + "px");
>          document.body.removeStyleClass("drawer-visible");
>          if ("updateStatusBarItems" in WebInspector.currentPanel)
>              WebInspector.currentPanel.updateStatusBarItems();
> @@ -145,9 +167,90 @@ WebInspector.Drawer.prototype = {
>              mainStatusBar.style.removeProperty("padding-left");
>              document.body.removeStyleClass("drawer-visible");
>              delete this._animating;
> +            delete this.currentAnimationInterval;
> +            this.state = WebInspector.Drawer.State.Hidden;
>          }
>  
> -        WebInspector.animateStyle(animations, window.event && window.event.shiftKey ? 2000 : 250, animationFinished.bind(this));
> +        this.currentAnimationInterval = WebInspector.animateStyle(animations, this._animationDuration(), animationFinished.bind(this));
> +    },
> +
> +    resize: function()
> +    {
> +        if (this.state === WebInspector.Drawer.State.Hidden)
> +            return;
> +
> +        var height;
> +        var mainElement = document.getElementById("main");
> +        if (this.state === WebInspector.Drawer.State.Variable) {
> +            height = parseInt(this.element.style.height);
> +            height = Number.constrain(height, Preferences.minConsoleHeight, window.innerHeight - mainElement.totalOffsetTop - Preferences.minConsoleHeight);
> +        } else
> +            height = window.innerHeight - this.toolbarElement.offsetHeight;
> +
> +        mainElement.style.bottom = height + "px";
> +        this.element.style.height = height + "px";
> +    },
> +
> +    enterPanelMode: function()
> +    {
> +        this._cancelAnimationIfNeeded();
> +        this.fullPanel = true;
> +        
> +        if (this.visible) {
> +            this.savedHeight = this.element.offsetHeight;
> +            var height = window.innerHeight - this.toolbarElement.offsetHeight;
> +            this._animateDrawerHeight(height, WebInspector.Drawer.State.Full);
> +        }
> +    },
> +
> +    exitPanelMode: function()
> +    {
> +        this._cancelAnimationIfNeeded();
> +        this.fullPanel = false;
> +
> +        if (this.visible) {
> +            // If this animation gets cancelled, we want the state of the drawer to be Variable,
> +            // so that the new animation can't do an immediate transition between Hidden/Full states.
> +            this.state = WebInspector.Drawer.State.Variable;
> +            var height = this.savedHeight;
> +            this._animateDrawerHeight(height, WebInspector.Drawer.State.Variable);
> +        }
> +    },
> +
> +    _cancelAnimationIfNeeded: function()
> +    {
> +        if (this._animating) {
> +            clearInterval(this.currentAnimationInterval);
> +            delete this._animating;
> +            delete this.currentAnimationInterval;
> +        }
> +    },
> +
> +    _animateDrawerHeight: function(height, finalState)
> +    {
> +        this._animating = true;
> +        var animations = [
> +            {element: this.element, end: {height: height}},
> +            {element: document.getElementById("main"), end: {bottom: height}}
> +        ];
> +
> +        function animationFinished()
> +        {
> +            delete this._animating;
> +            delete this.currentAnimationInterval;
> +            this.state = finalState;
> +        }
> +
> +        this.currentAnimationInterval = WebInspector.animateStyle(animations, this._animationDuration(), animationFinished.bind(this));
> +    },
> +
> +    _animationDuration: function()
> +    {
> +        // Immediate if going between Hidden and Full in full panel mode
> +        if (this.fullPanel && (this.state === WebInspector.Drawer.State.Hidden || this.state === WebInspector.Drawer.State.Full))
> +            return 0;
> +
> +        return (window.event && window.event.shiftKey ? 2000 : 250);
>      },
>  
>      _safelyRemoveChildren: function()
> @@ -165,10 +268,10 @@ WebInspector.Drawer.prototype = {
>  
>      _startStatusBarDragging: function(event)
>      {
> -        if (!this.visible || event.target !== document.getElementById("main-status-bar"))
> +        if (!this.visible || event.target !== this.mainStatusBar)
>              return;
>  
> -        WebInspector.elementDragStart(document.getElementById("main-status-bar"), this._statusBarDragging.bind(this), this._endStatusBarDragging.bind(this), event, "row-resize");
> +        WebInspector.elementDragStart(this.mainStatusBar, this._statusBarDragging.bind(this), this._endStatusBarDragging.bind(this), event, "row-resize");
>  
>          this._statusBarDragOffset = event.pageY - this.element.totalOffsetTop;
>  
> @@ -178,7 +281,6 @@ WebInspector.Drawer.prototype = {
>      _statusBarDragging: function(event)
>      {
>          var mainElement = document.getElementById("main");
> -
>          var height = window.innerHeight - event.pageY + this._statusBarDragOffset;
>          height = Number.constrain(height, Preferences.minConsoleHeight, window.innerHeight - mainElement.totalOffsetTop - Preferences.minConsoleHeight);
>  
> @@ -193,6 +295,7 @@ WebInspector.Drawer.prototype = {
>      {
>          WebInspector.elementDragEnd(event);
>  
> +        this.savedHeight = this.element.offsetHeight;
>          delete this._statusBarDragOffset;
>  
>          event.stopPropagation();
> @@ -200,3 +303,9 @@ WebInspector.Drawer.prototype = {
>  }
>  
>  WebInspector.Drawer.prototype.__proto__ = WebInspector.View.prototype;
> +
> +WebInspector.Drawer.State = {
> +    Hidden: 0,
> +    Variable: 1,
> +    Full: 2
> +};
> diff --git a/WebCore/inspector/front-end/WebKit.qrc b/WebCore/inspector/front-end/WebKit.qrc
> index 53917f6..dbf406c 100644
> --- a/WebCore/inspector/front-end/WebKit.qrc
> +++ b/WebCore/inspector/front-end/WebKit.qrc
> @@ -9,6 +9,7 @@
>      <file>CallStackSidebarPane.js</file>
>      <file>ChangesView.js</file>
>      <file>Color.js</file>
> +    <file>ConsolePanel.js</file>
>      <file>ConsoleView.js</file>
>      <file>CookieItemsView.js</file>
>      <file>Database.js</file>
> @@ -75,6 +76,7 @@
>      <file>Images/closeButtons.png</file>
>      <file>Images/consoleButtonGlyph.png</file>
>      <file>Images/cookie.png</file>
> +    <file>Images/consoleIcon.png</file>

Please add this into WebCore.gypi as well!

>      <file>Images/database.png</file>
>      <file>Images/databaseTable.png</file>
>      <file>Images/debuggerContinue.png</file>
> diff --git a/WebCore/inspector/front-end/inspector.css b/WebCore/inspector/front-end/inspector.css
> index 035dc13..50e7ef6 100644
> --- a/WebCore/inspector/front-end/inspector.css
> +++ b/WebCore/inspector/front-end/inspector.css
> @@ -215,6 +215,10 @@ body.attached #search-results-matches {
>      background-image: url(Images/profilesIcon.png);
>  }
>  
> +.toolbar-item.console .toolbar-icon {
> +    background-image: url(Images/consoleIcon.png);
> +}
> +
>  #close-button-left, #close-button-right {
>      width: 14px;
>      height: 14px;
> diff --git a/WebCore/inspector/front-end/inspector.html b/WebCore/inspector/front-end/inspector.html
> index a609f89..489996c 100644
> --- a/WebCore/inspector/front-end/inspector.html
> +++ b/WebCore/inspector/front-end/inspector.html
> @@ -79,6 +79,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
>      <script type="text/javascript" src="ScriptsPanel.js"></script>
>      <script type="text/javascript" src="StoragePanel.js"></script>
>      <script type="text/javascript" src="ProfilesPanel.js"></script>
> +    <script type="text/javascript" src="ConsolePanel.js"></script>
>      <script type="text/javascript" src="ResourceView.js"></script>
>      <script type="text/javascript" src="SourceFrame.js"></script>
>      <script type="text/javascript" src="SourceView.js"></script>
> @@ -108,7 +109,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
>      </div>
>      <div id="main">
>          <div id="main-panels" tabindex="0" spellcheck="false"></div>
> -        <div id="main-status-bar" class="status-bar"><div id="anchored-status-bar-items"><button id="dock-status-bar-item" class="status-bar-item toggled"><div class="glyph"></div><div class="glyph shadow"></div></button><button id="console-status-bar-item" class="status-bar-item"><div class="glyph"></div><div class="glyph shadow"></div></button><button id="changes-status-bar-item" class="status-bar-item hidden"></button><div id="count-items"><div id="changes-count" class="hidden"></div><div id="error-warning-count" class="hidden"></div></div></div></div>
> +        <div id="main-status-bar" class="status-bar"><div id="anchored-status-bar-items"><button id="dock-status-bar-item" class="status-bar-item"><div class="glyph"></div><div class="glyph shadow"></div></button><button id="console-status-bar-item" class="status-bar-item"><div class="glyph"></div><div class="glyph shadow"></div></button><button id="changes-status-bar-item" class="status-bar-item hidden"></button><div id="count-items"><div id="changes-count" class="hidden"></div><div id="error-warning-count" class="hidden"></div></div></div></div>

Why did this change?

>      </div>
>      <div id="drawer">
>          <div id="console-view"><div id="console-messages"><div id="console-prompt" spellcheck="false"><br></div></div></div>
> diff --git a/WebCore/inspector/front-end/inspector.js b/WebCore/inspector/front-end/inspector.js
> index b632c2c..0be0804 100644
> --- a/WebCore/inspector/front-end/inspector.js
> +++ b/WebCore/inspector/front-end/inspector.js
> @@ -72,6 +72,7 @@ var WebInspector = {
>      resourceURLMap: {},
>      cookieDomains: {},
>      missingLocalizedStrings: {},
> +    pendingDispatches: 0,
>  
>      get previousFocusElement()
>      {
> @@ -170,6 +171,8 @@ var WebInspector = {
>  
>          if (hiddenPanels.indexOf("storage") === -1 && hiddenPanels.indexOf("databases") === -1)
>              this.panels.storage = new WebInspector.StoragePanel();
> +        if (hiddenPanels.indexOf("console") === -1)
> +            this.panels.console = new WebInspector.ConsolePanel();
>      },
>  
>      _loadPreferences: function()
> @@ -396,7 +399,6 @@ WebInspector.loaded = function()
>      document.body.addStyleClass("port-" + port);
>  
>      this._loadPreferences();
> -    this.pendingDispatches = 0;
>  
>      this.drawer = new WebInspector.Drawer();
>      this.console = new WebInspector.ConsoleView(this.drawer);
> @@ -535,6 +537,7 @@ WebInspector.windowResize = function(event)
>  {
>      if (this.currentPanel && this.currentPanel.resize)
>          this.currentPanel.resize();
> +    this.drawer.resize();
>  }
>  
>  WebInspector.windowFocused = function(event)
> @@ -624,6 +627,9 @@ WebInspector.documentKeyDown = function(event)
>  
>          switch (event.keyIdentifier) {
>              case "U+001B": // Escape key
> +                if (this.drawer.fullPanel)
> +                    return;
> +
>                  this.drawer.visible = !this.drawer.visible;
>                  event.preventDefault();
>                  break;
> @@ -749,29 +755,31 @@ WebInspector.mainCopy = function(event)
>          this.currentPanel.handleCopyEvent(event);
>  }
>  
> -WebInspector.animateStyle = function(animations, duration, callback, complete)
> +WebInspector.animateStyle = function(animations, duration, callback)
>  {
> -    if (complete === undefined)
> -        complete = 0;
> -    var slice = (1000 / 30); // 30 frames per second
> +    var interval;
> +    var complete = 0;
> +
> +    const intervalDuration = (1000 / 30); // 30 frames per second.
> +    const animationsLength = animations.length;
> +    const propertyUnit = {opacity: ""};
> +    const defaultUnit = "px";
>  
> -    var defaultUnit = "px";
> -    var propertyUnit = {opacity: ""};
> +    function cubicInOut(t, b, c, d)
> +    {
> +        if ((t/=d/2) < 1) return c/2*t*t*t + b;
> +        return c/2*((t-=2)*t*t + 2) + b;
> +    }
>  
> -    for (var i = 0; i < animations.length; ++i) {
> +    // Pre-process animations.
> +    for (var i = 0; i < animationsLength; ++i) {
>          var animation = animations[i];
> -        var element = null;
> -        var start = null;
> -        var current = null;
> -        var end = null;
> -        var key = null;
> +        var element = null, start = null, current = null, end = null, key = null;
>          for (key in animation) {
>              if (key === "element")
>                  element = animation[key];
>              else if (key === "start")
>                  start = animation[key];
> -            else if (key === "current")
> -                current = animation[key];
>              else if (key === "end")
>                  end = animation[key];
>          }
> @@ -779,49 +787,54 @@ WebInspector.animateStyle = function(animations, duration, callback, complete)
>          if (!element || !end)
>              continue;
>  
> -        var computedStyle = element.ownerDocument.defaultView.getComputedStyle(element);
>          if (!start) {
> +            var computedStyle = element.ownerDocument.defaultView.getComputedStyle(element);
>              start = {};
>              for (key in end)
>                  start[key] = parseInt(computedStyle.getPropertyValue(key));
>              animation.start = start;
> -        } else if (complete == 0)
> +        } else
>              for (key in start)
>                  element.style.setProperty(key, start[key] + (key in propertyUnit ? propertyUnit[key] : defaultUnit));
> +    }
>  
> -        if (!current) {
> -            current = {};
> -            for (key in start)
> -                current[key] = start[key];
> -            animation.current = current;
> -        }
> -
> -        function cubicInOut(t, b, c, d)
> -        {
> -            if ((t/=d/2) < 1) return c/2*t*t*t + b;
> -            return c/2*((t-=2)*t*t + 2) + b;
> +    function animateLoop()
> +    {
> +        // Advance forward.
> +        complete += intervalDuration;
> +        var next = complete + intervalDuration;
> +
> +        // Make style changes.
> +        for (var i = 0; i < animationsLength; ++i) {
> +            var animation = animations[i];
> +            var element = animation.element;
> +            var start = animation.start;
> +            var end = animation.end;
> +            if (!element || !end)
> +                continue;
> +
> +            var style = element.style;
> +            for (key in end) {
> +                var endValue = end[key];
> +                if (next < duration) {
> +                    var startValue = start[key];
> +                    var newValue = cubicInOut(complete, startValue, endValue - startValue, duration);
> +                    style.setProperty(key, newValue + (key in propertyUnit ? propertyUnit[key] : defaultUnit));
> +                } else
> +                    style.setProperty(key, endValue + (key in propertyUnit ? propertyUnit[key] : defaultUnit));
> +            }
>          }
>  
> -        var style = element.style;
> -        for (key in end) {
> -            var startValue = start[key];
> -            var currentValue = current[key];
> -            var endValue = end[key];
> -            if ((complete + slice) < duration) {
> -                var delta = (endValue - startValue) / (duration / slice);
> -                var newValue = cubicInOut(complete, startValue, endValue - startValue, duration);
> -                style.setProperty(key, newValue + (key in propertyUnit ? propertyUnit[key] : defaultUnit));
> -                current[key] = newValue;
> -            } else {
> -                style.setProperty(key, endValue + (key in propertyUnit ? propertyUnit[key] : defaultUnit));
> -            }
> +        // End condition.
> +        if (complete >= duration) {
> +            clearInterval(interval);
> +            if (callback)
> +                callback();
>          }
>      }
>  
> -    if (complete < duration)
> -        setTimeout(WebInspector.animateStyle, slice, animations, duration, callback, complete + slice);
> -    else if (callback)
> -        callback();
> +    interval = setInterval(animateLoop, intervalDuration);
> +    return interval;
>  }
>  
>  WebInspector.updateSearchLabel = function()
> @@ -841,6 +854,7 @@ WebInspector.updateSearchLabel = function()
>  WebInspector.toggleAttach = function()
>  {
>      this.attached = !this.attached;
> +    this.drawer.resize();
>  }
>  
>  WebInspector.toolbarDragStart = function(event)
> @@ -964,6 +978,11 @@ WebInspector.showStoragePanel = function()
>      this.currentPanel = this.panels.storage;
>  }
>  
> +WebInspector.showConsolePanel = function()
> +{
> +    this.currentPanel = this.panels.console;
> +}
> +
>  WebInspector.addResource = function(identifier, payload)
>  {
>      var resource = new WebInspector.Resource(
> @@ -1054,7 +1073,7 @@ WebInspector.updateResource = function(identifier, payload)
>              resource.responseReceivedTime = payload.responseReceivedTime;
>          if (payload.endTime)
>              resource.endTime = payload.endTime;
> -        
> +
>          if (payload.loadEventTime) {
>              // This loadEventTime is for the main resource, and we want to show it
>              // for all resources on this page. This means we want to set it as a member
> @@ -1062,7 +1081,7 @@ WebInspector.updateResource = function(identifier, payload)
>              if (this.panels.resources)
>                  this.panels.resources.mainResourceLoadTime = payload.loadEventTime;
>          }
> -        
> +
>          if (payload.domContentEventTime) {
>              // This domContentEventTime is for the main resource, so it should go in
>              // the resources panel for the same reasons as above.
> @@ -1248,23 +1267,23 @@ WebInspector.log = function(message)
>  {
>      // remember 'this' for setInterval() callback
>      var self = this;
> -    
> +
>      // return indication if we can actually log a message
>      function isLogAvailable()
>      {
>          return WebInspector.ConsoleMessage && WebInspector.ObjectProxy && self.console;
>      }
> -    
> +
>      // flush the queue of pending messages
>      function flushQueue()
>      {
>          var queued = WebInspector.log.queued;
> -        if (!queued) 
> +        if (!queued)
>              return;
> -            
> +
>          for (var i = 0; i < queued.length; ++i)
>              logMessage(queued[i]);
> -        
> +
>          delete WebInspector.log.queued;
>      }
>  
> @@ -1274,26 +1293,26 @@ WebInspector.log = function(message)
>      {
>          if (!isLogAvailable())
>              return;
> -            
> +
>          clearInterval(WebInspector.log.interval);
>          delete WebInspector.log.interval;
> -        
> +
>          flushQueue();
>      }
> -    
> +
>      // actually log the message
>      function logMessage(message)
>      {
>          var repeatCount = 1;
>          if (message == WebInspector.log.lastMessage)
>              repeatCount = WebInspector.log.repeatCount + 1;
> -    
> +
>          WebInspector.log.lastMessage = message;
>          WebInspector.log.repeatCount = repeatCount;
> -        
> +
>          // ConsoleMessage expects a proxy object
>          message = new WebInspector.ObjectProxy(null, [], 0, message, false);
> -        
> +
>          // post the message
>          var msg = new WebInspector.ConsoleMessage(
>              WebInspector.ConsoleMessage.MessageSource.Other,
> @@ -1304,20 +1323,20 @@ WebInspector.log = function(message)
>              null,
>              repeatCount,
>              message);
> -    
> +
>          self.console.addMessage(msg);
>      }
> -    
> +
>      // if we can't log the message, queue it
>      if (!isLogAvailable()) {
>          if (!WebInspector.log.queued)
>              WebInspector.log.queued = [];
> -            
> +
>          WebInspector.log.queued.push(message);
> -        
> +
>          if (!WebInspector.log.interval)
>              WebInspector.log.interval = setInterval(flushQueueIfAvailable, 1000);
> -        
> +
>          return;
>      }
>  
> @@ -1457,7 +1476,8 @@ WebInspector.linkifyStringAsFragment = function(string)
>      return container;
>  }
>  
> -WebInspector.showProfileForURL = function(url) {
> +WebInspector.showProfileForURL = function(url)
> +{
>      WebInspector.showProfilesPanel();
>      WebInspector.panels.profiles.showProfileForURL(url);
>  }
Comment 18 Pavel Feldman 2009-11-19 23:58:25 PST
Sorry about not cleaning up uncommented parts. I was checking if bugzilla does it for me.
Comment 19 Paul Bakaus 2009-11-20 00:42:01 PST
Joseph, I just saw you wrote your own animateStyle method to animate (I did it a couple times as well, wrote all the stuff for jQuery UI :) ). Now since we're effectively addressing Webkit only, I was wondering it it wouldn't be more efficient to use CSS Animations through the JavaScript exposed functions?
Comment 20 Joseph Pecoraro 2009-11-20 07:12:38 PST
> > +        this.previousConsoleState = WebInspector.drawer.state;
> 
> This can be private (this._previousConsoleState)

Done.


> > +        if (this.previousConsoleState === WebInspector.Drawer.State.Hidden) {
> > +            WebInspector.drawer.visible = false;
> > +            WebInspector.drawer.fullPanel = false;
> 
> You have nice methods that encapsulate drawer behavior for enterPanelMode nad
> exitPanelMode. Should you introduce some reset method as well and hide visible
> and fullPanel?

Done. I called this immediatelyExitPanelMode.


> > +    this.savedHeight = 0;
> > +    this.state = WebInspector.Drawer.State.Hidden;
> > +    this.fullPanel = false;
> > +
> > +    this.mainElement = document.getElementById("main");
> > +    this.toolbarElement = document.getElementById("toolbar");
> 
> Same here - you do access some of the drawer properties from the outside. Would
> be nice to distinguish between public and private ones.

I left the element's alone. Since that seems to be precedence. savedHeight is now private.


> > +    set savedHeight(x)
> > +    {
> > +        this._savedHeight = x;
> > +    },
> 
> I don't think you need setter for this. I hope you mutate from within this
> class only, you should just assign to this._savedHeight.

Done.


> > +            delete this.currentAnimationInterval;
> > +        ...
> > +        this.currentAnimationInterval = WebInspector.animateStyle(animations, this._animationDuration(), animationFinished.bind(this));
> 
> Ditto

Done. (made private).


> > +    <file>ConsolePanel.js</file>
> > +    <file>Images/consoleIcon.png</file>
> 
> Please add this into WebCore.gypi as well!

Already did (first file after ChangeLog).


> > -        <div id="main-status-bar" class="status-bar"><div id="anchored-status-bar-items"><button id="dock-status-bar-item" class="status-bar-item toggled"><div class="glyph"></div><div class="glyph shadow"></div></button><button id="console-status-bar-item" class="status-bar-item"><div class="glyph"></div><div class="glyph shadow"></div></button><button id="changes-status-bar-item" class="status-bar-item hidden"></button><div id="count-items"><div id="changes-count" class="hidden"></div><div id="error-warning-count" class="hidden"></div></div></div></div>
> > +        <div id="main-status-bar" class="status-bar"><div id="anchored-status-bar-items"><button id="dock-status-bar-item" class="status-bar-item"><div class="glyph"></div><div class="glyph shadow"></div></button><button id="console-status-bar-item" class="status-bar-item"><div class="glyph"></div><div class="glyph shadow"></div></button><button id="changes-status-bar-item" class="status-bar-item hidden"></button><div id="count-items"><div id="changes-count" class="hidden"></div><div id="error-warning-count" class="hidden"></div></div></div></div>
> 
> Why did this change?

I removed class "toggle" on the dock/undock button. The class does nothing. It should likely have been "toggled-on", however we are all very used to it being toggled off, that it felt much more natural being off. To be clear, after this change, nothing will be different then it already is.
Comment 21 Joseph Pecoraro 2009-11-20 07:18:31 PST
Created attachment 43578 [details]
[PATCH] Console Panel (Even Better)

Addresses Pavel's comments.
Comment 22 Joseph Pecoraro 2009-11-20 07:20:13 PST
Ahh, my latest patch I forgot to remove the image from the diff. You can just ignore the binary diff for the image.  I will end up landing this manually and use whatever image I am given.
Comment 23 Timothy Hatcher 2009-11-20 09:16:50 PST
Created attachment 43588 [details]
Console Panel Icon
Comment 24 Timothy Hatcher 2009-11-20 09:32:27 PST
(In reply to comment #19)
> Joseph, I just saw you wrote your own animateStyle method to animate (I did it
> a couple times as well, wrote all the stuff for jQuery UI :) ). Now since we're
> effectively addressing Webkit only, I was wondering it it wouldn't be more
> efficient to use CSS Animations through the JavaScript exposed functions?

Back when I wrote the animateStyle method, CSS animations didn't exist. We have switched a few uses over to use CSS animations, but there are somethings that are just easier with this method. (Or imposible currently with CSS animations.)
Comment 25 Timothy Hatcher 2009-11-20 09:45:57 PST
Comment on attachment 43578 [details]
[PATCH] Console Panel (Even Better)

> +        var element = null, start = null, current = null, end = null, key = null;

You don't need current in this list.

Icon attached.
Comment 26 Joseph Pecoraro 2009-11-20 11:23:17 PST
Landed in http://trac.webkit.org/changeset/51246
r51246 = d631fe866617cc286f07337f4e19cebc1b0cda5a
Comment 27 M Henderson 2009-11-30 15:07:37 PST
Wow, thanks for the quick fix. A larger console area is well welcomed. In my opinion, it is still behind the one used in firebug. 

A couple of things
1. having the code mixed in with the results of the code. Firebug offers a separate section to write in and one to see the results. I feel that something along these lines, as minor as it is, would make the console tab a bit more useful.
2. Having to hit a control key to do line returns. I feel that the firebug way of having to hit a control key (command os x, control win) to execute the script is a more elegant solution.
3. Is it possible to add in tabbing support?

Again, I love the work that you guys are doing and I thank you for it. These are just a few suggestions to make the product a bit better.
Comment 28 Joseph Pecoraro 2009-11-30 15:18:37 PST
(In reply to comment #27)
> 1. having the code mixed in with the results of the code. Firebug offers a
> separate section to write in and one to see the results. I feel that something
> along these lines, as minor as it is, would make the console tab a bit more
> useful.

See bug 30553 for some ideas in this direction. Its currently referred to as "Snippets". This feature would hopefully handle all of your suggestions =).

> 2. Having to hit a control key to do line returns. I feel that the firebug way
> of having to hit a control key (command os x, control win) to execute the
> script is a more elegant solution.

For mac users, ⌥+Enter is a well known (or should be) for adding new lines. Again, consider the Snippets feature, which would be a text area.

> 3. Is it possible to add in tabbing support?

You mean tab as in whitespace? Right now tab is used for autocompletion. I think users would prefer tab for completion over whitespace in the Console. It would probably be good for Snippets though.