| author | Kris De Volder | 2012-05-01 16:20:51 (EDT) |
|---|---|---|
| committer | Grant Gayed | 2012-05-09 14:09:40 (EDT) |
| commit | 56e9bc64bb5f4b267672f7dee43872509cb5421d (patch) (side-by-side diff) | |
| tree | 9840c5e2d67d670a207a2e2b7fee0bc6f8557f62 | |
| parent | b997ef7cf98fa8615ac4560daf834bb4b59fbba6 (diff) | |
| download | org.eclipse.orion.client-56e9bc64bb5f4b267672f7dee43872509cb5421d.zip org.eclipse.orion.client-56e9bc64bb5f4b267672f7dee43872509cb5421d.tar.gz org.eclipse.orion.client-56e9bc64bb5f4b267672f7dee43872509cb5421d.tar.bz2 | |
initial console release
14 files changed, 1312 insertions, 0 deletions
diff --git a/bundles/org.eclipse.orion.client.console/.project b/bundles/org.eclipse.orion.client.console/.project new file mode 100644 index 0000000..bf39786 --- a/dev/null +++ b/bundles/org.eclipse.orion.client.console/.project @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>org.eclipse.orion.client.console</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.wst.jsdt.core.javascriptValidator</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.ManifestBuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.wst.jsdt.core.jsNature</nature> + <nature>org.eclipse.pde.PluginNature</nature> + </natures> +</projectDescription> diff --git a/bundles/org.eclipse.orion.client.console/.settings/org.eclipse.pde.core.prefs b/bundles/org.eclipse.orion.client.console/.settings/org.eclipse.pde.core.prefs new file mode 100644 index 0000000..30e026c --- a/dev/null +++ b/bundles/org.eclipse.orion.client.console/.settings/org.eclipse.pde.core.prefs @@ -0,0 +1,4 @@ +#Tue Jan 18 14:23:15 CET 2011 +eclipse.preferences.version=1 +pluginProject.extensions=false +resolve.requirebundle=false diff --git a/bundles/org.eclipse.orion.client.console/META-INF/MANIFEST.MF b/bundles/org.eclipse.orion.client.console/META-INF/MANIFEST.MF new file mode 100644 index 0000000..a73c911 --- a/dev/null +++ b/bundles/org.eclipse.orion.client.console/META-INF/MANIFEST.MF @@ -0,0 +1,8 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %Bundle-Name +Bundle-SymbolicName: org.eclipse.orion.client.console;singleton:=true +Bundle-Version: 0.0.1.qualifier +Bundle-ActivationPolicy: lazy +Bundle-Vendor: %Bundle-Vendor +Bundle-Localization: bundle diff --git a/bundles/org.eclipse.orion.client.console/about.html b/bundles/org.eclipse.orion.client.console/about.html new file mode 100644 index 0000000..8657dfd --- a/dev/null +++ b/bundles/org.eclipse.orion.client.console/about.html @@ -0,0 +1,29 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" +"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/> +<title>About</title> +</head> +<body lang="EN-US"> +<h2>About This Content</h2> + +<p>April 26, 2011</p> +<h3>License</h3> + +<p>The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +<a href="http://www.eclipse.org/legal/epl-v10.html">Eclipse Public License Version 1.0</a> +("EPL"), and the <a href="http://www.eclipse.org/org/documents/edl-v10.html"> +Eclipse Distribution License Version 1.0</a> ("EDL"). +For purposes of the EPL and EDL, "Program" will mean the Content.</p> + +<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content +and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p> + +</body> +</html> diff --git a/bundles/org.eclipse.orion.client.console/build.properties b/bundles/org.eclipse.orion.client.console/build.properties new file mode 100644 index 0000000..b5c1d01 --- a/dev/null +++ b/bundles/org.eclipse.orion.client.console/build.properties @@ -0,0 +1,23 @@ +############################################################################### +# Copyright (c) 2011 IBM Corporation and others. +# All rights reserved. This program and the accompanying materials are made +# available under the terms of the Eclipse Public License v1.0 +# (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution +# License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). +# +# Contributors: IBM Corporation - initial API and implementation +############################################################################### + +bin.includes = META-INF/,\ + web/,\ + bundle.properties,\ + about.html,\ + submodules/gcli/lib/,\ + plugin.xml +src.includes = web/,\ + about.html,\ + bundle.properties,\ + submodules/gcli/lib/gcli/ +bin.excludes = submodules/gcli/lib/demo/,\ + submodules/gcli/lib/gclitest/,\ + submodules/gcli/lib/test/ diff --git a/bundles/org.eclipse.orion.client.console/bundle.properties b/bundles/org.eclipse.orion.client.console/bundle.properties new file mode 100644 index 0000000..77f2a02 --- a/dev/null +++ b/bundles/org.eclipse.orion.client.console/bundle.properties @@ -0,0 +1,2 @@ +Bundle-Vendor = Eclipse.org - Orion +Bundle-Name = Orion Commmand Line UI (Incubation) diff --git a/bundles/org.eclipse.orion.client.console/plugin.xml b/bundles/org.eclipse.orion.client.console/plugin.xml new file mode 100644 index 0000000..1bc6396 --- a/dev/null +++ b/bundles/org.eclipse.orion.client.console/plugin.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+ <extension
+ point="org.eclipse.equinox.http.registry.httpcontexts">
+ <httpcontext
+ id="org.eclipse.orion.server.configurator.httpcontext.console">
+ <resource-mapping
+ path="/web/console">
+ </resource-mapping>
+ </httpcontext>
+ <httpcontext
+ id="org.eclipse.orion.server.configurator.httpcontext.console.gcli">
+ <resource-mapping
+ path="/submodules/gcli">
+ </resource-mapping>
+ </httpcontext>
+ </extension>
+ <extension
+ point="org.eclipse.equinox.http.registry.resources">
+ <resource
+ alias="/console"
+ httpcontextId="org.eclipse.orion.server.configurator.httpcontext.console">
+ </resource>
+ <resource
+ alias="/console/gcli"
+ httpcontextId="org.eclipse.orion.server.configurator.httpcontext.console.gcli">
+ </resource>
+ </extension>
+</plugin>
diff --git a/bundles/org.eclipse.orion.client.console/submodules/gcli b/bundles/org.eclipse.orion.client.console/submodules/gcli new file mode 160000 +Subproject 52e9d9602f5046a0b9c1399297d653febf16657 diff --git a/bundles/org.eclipse.orion.client.console/web/console/current-directory.js b/bundles/org.eclipse.orion.client.console/web/console/current-directory.js new file mode 100644 index 0000000..1980688 --- a/dev/null +++ b/bundles/org.eclipse.orion.client.console/web/console/current-directory.js @@ -0,0 +1,130 @@ +/*global require define setTimeout */ +/** + * This module provides utility methods to retrieve information about directorie. It also keeps + * track of the 'current' directory state by using the 'dojo.hash()' function to store and retrieve + * the current directory location from the page URL. + */ +define(['dojo', 'orion/bootstrap', 'orion/fileClient'], function (dojo, mBootstrap, mFileClient) { + + var fileClient; + var exports = {}; + + //The current path. I.e. the working dir relative to which we will execute commands on the server. + var currentTreeNode = null; + + function withWorkspace(k) { + fileClient.loadWorkspace('').then(k); + } + exports.withWorkspace = withWorkspace; + + /** + * Make sure that there is a currentTreeNode and call given callback on the tree node + * as soon as its available. + */ + function withCurrentTreeNode(doit) { + if (currentTreeNode===null) { + var location = dojo.hash() || ""; + fileClient.loadWorkspace(location).then(function (node) { + currentTreeNode = node; + doit(node); + }); + } else { + //Wrapped in a setTimeout to ensure it always executed as later scheduled event. + //otherwise the execution order will be different depending on whether currentTreeNode==null + setTimeout(function () { + doit(currentTreeNode); + }); + } + } + exports.withCurrentTreeNode = withCurrentTreeNode; + + /** + * Returns true if string is a string that ends with the string suffix. + */ + function endsWith(string, suffix) { + if (typeof(string)==='string' && typeof(suffix)==='string') { + var loc = string.lastIndexOf(suffix); + return (loc + suffix.length) === string.length; + } + return false; + } + + /** + * Get the location of a given node's parent node. May return null if the node is a workspace node + * so it doesn't have a parent. + * <p> + * Warning: a valid parent location is the empty String '' which indicates the 'root' location. + * To check whether a valid parent was returned use 'if (loc!==null)' rather than 'if (loc)'. + * The empty String will count as 'false' in if tests! + */ + function getParentLocation(node) { + if (node.Parents && node.Parents.length>0) { + return node.Parents[0].Location; + } else { + //TODO: Hack allert! Should not be using URL hackery to determine parent location + // but it seems sometimes we don't have a choice because the Parent's attribute is missing. + // Should investigate precisely how breadcrumbs does this. + var location = node.Location; + var parentLocation = null; + if (endsWith(location,'/')) { + location = location.slice(0, location.length-1); + } + if (location) { + var lastSlash = location.lastIndexOf('/'); + if (lastSlash>=0) { + parentLocation = location.slice(0, lastSlash+1); + if (parentLocation==='/file/') { + parentLocation = ''; + } else if (parentLocation==='/workspace/') { + parentLocation = null; + } + } + } + return parentLocation; + } + } + exports.getParentLocation = getParentLocation; + + function setCurrentTreeNode(node) { + currentTreeNode = node; + if (currentTreeNode && currentTreeNode.Location) { + dojo.hash(currentTreeNode.Location); + } + } + exports.setCurrentTreeNode = setCurrentTreeNode; + + /** + * Calls the callback function 'k' with the children of a given node. + * If the children are available the callback function is called immediately otherwise + * the children will be retrieved and the callback function called whenever the children + * become available. + */ + function withChildren(node, k) { + if (node.Children) { + k(node.Children); + } else if (node.ChildrenLocation) { + fileClient.fetchChildren(node.ChildrenLocation).then(function (children) { + node.Children = children; // cache for later. + k(children); + }); + } + } + exports.withChildren = withChildren; + + function withCurrentChildren(k) { + withCurrentTreeNode(function (node) { + withChildren(node, k); + }); + } + exports.withCurrentChildren = withCurrentChildren; + + dojo.ready(function() { + mBootstrap.startup().then(function(core) { + var serviceRegistry = core.serviceRegistry; + fileClient = new mFileClient.FileClient(serviceRegistry); + }); + }); + + return exports; + +});
\ No newline at end of file diff --git a/bundles/org.eclipse.orion.client.console/web/console/directory-type.js b/bundles/org.eclipse.orion.client.console/web/console/directory-type.js new file mode 100644 index 0000000..92ecc99 --- a/dev/null +++ b/bundles/org.eclipse.orion.client.console/web/console/directory-type.js @@ -0,0 +1,291 @@ +/******************************************************************************* + * @license + * Copyright (c) 2012 VMWare and others. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution + * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). + * + * Contributors: + * Kris De Volder (VMWare) - initial API and implementation + *******************************************************************************/ +/*global define require setTimeout*/ +define(['gcli/types', 'gcli/types/basic', 'gcli/ui/field', 'gcli/argument', 'gcli/util', 'dojo', 'gcli/cli', +'gcli/ui/menu', 'console/current-directory'], function() { + + var dojo = require('dojo'); + var registerType = require('gcli/types').registerType; + var StringType = require('gcli/types/basic').StringType; + var Conversion = require('gcli/types').Conversion; + var Status = require('gcli/types').Status; + var Field = require('gcli/ui/field').Field; + var Argument = require('gcli/argument').Argument; + var addField = require('gcli/ui/field').addField; + var dom = require('gcli/util').dom; + var createEvent = require('gcli/util').createEvent; +// var Assignment = require('gcli/cli').Assignment; + var Menu = require('gcli/ui/menu').Menu; + var withCurrentChildren = require('console/current-directory').withCurrentChildren; + + var cache = {}; + + /** + * Returns true if string is a string that starts with the given prefix. + */ + function startsWith(string, prefix) { + if (typeof(string)==='string' && typeof(prefix)==='string') { + return string.indexOf(prefix)===0; + } + return false; + } + + function withValidDirs(k) { + withCurrentChildren(function (nodes) { + var names = ['..']; + for (var i = 0; i < nodes.length; i++) { + var node = nodes[i]; + if (node.Directory) { + names.push(node.Name); + } + } + k(names); + }); + } + + function computeCompletions(text, validDirs) { + var completions = []; + for (var i = 0; i < validDirs.length; i++) { + var candidate = validDirs[i]; + if (startsWith(candidate, text)) { + completions.push({ + name: candidate, + description: candidate, + value: candidate + }); + } + } + return completions; + } + + /** + * Gets list of completions, may return null if the list can't be computed + * synchronously. + */ + function getCompletions(text) { + if (cache.completions && cache.text===text) { + return cache.completions; + } + if (cache.validDirs) { + //Do a quick computation from the list of dirs + cache.completions = computeCompletions(text, cache.validDirs); + cache.text = text; + return cache.completions; + } + //Values will be cached in future... but we have no completions at this time. + //We couldn't get the list just from cached values... + //try to prefetch cache for future use. + withValidDirs(function (validDirs) { + cache.validDirs = validDirs; + }); + return null; + } + + /** + * Gets list of completions passing the result to callback function k. + * Will asynchronously fetch needed data if required. + */ + function withCompletions(text, k) { + var completions = getCompletions(text); + if (completions) { + k(completions); + } else { + withValidDirs(function (validDirs) { + cache.validDirs = validDirs; + k(getCompletions(text)); + }); + } + } + + function find(array, pred) { + for (var i = 0; i < array.length; i++) { + if (pred(array[i])) { + return array[i]; + } + } + return null; + } + + /** + * called to create a Conversion with a known list of predictions. + */ + function createConversion(str, arg, completions) { + var exactMatch = find(completions, function(el) { + return el.name === str; + }); + var message; + var status = Status.COMPLETE; //Default in case we forgte to set it. + if (exactMatch) { + status = Status.COMPLETE; + } else if (completions!==null && completions.length>0) { + status = Status.INCOMPLETE; + } else { + status = Status.ERROR; + message = "'"+str+"'"+" is not a valid directory"; + } + return new Conversion( + //value, + str, + //arg, + arg, + //status, + status, + //message, + message, + //predictions + completions + ); + } + + function DirectoryType(typeSpec) { + if (Object.keys(typeSpec).length > 0) { + throw new Error('DirectoryType can not be customized'); + } + } + + DirectoryType.prototype = Object.create(StringType.prototype); + DirectoryType.prototype.name = 'directory'; + + DirectoryType.prototype.parse = function (arg) { + var str = arg.text || ""; + //var prefix = arg.prefix || ""; + var completions = getCompletions(str); + if (completions!==null) { + return createConversion(str, arg, completions); + } else { + //The completions aren't available yet. We should try to return a Conversion that + //still allows user to edit, but without predictions. + //Also we add a 'then' method allowing access to the actual conversion via a callback. + var deferredConversion = new Conversion( + //value, + str, + //arg, + arg, + //status, + Status.INCOMPLETE, + //message, + undefined, + //predictions + completions + ); + deferredConversion.then = function(callback) { + withCompletions(str, function (completions) { + callback(createConversion(str, arg, completions)); + }); + }; + return deferredConversion; + } + }; + registerType(DirectoryType); + + /** + * A field that allows editing of directories. Basically, this is a + * String field with a menu attached to show the predictions. + */ + function DirectoryField(type, options) { + Field.call(this, type, options); + + this.onInputChange = this.onInputChange.bind(this); + this.arg = new Argument(); + + this.element = dom.createElement(this.document, 'div'); + + this.input = dom.createElement(this.document, 'input'); + this.input.type = 'text'; + this.input.addEventListener('keyup', this.onInputChange, false); + this.input.classList.add('gcli-field'); + this.input.classList.add('gcli-field-directory'); + this.element.appendChild(this.input); + + this.menu = new Menu({ document: this.document, field: true }); + this.element.appendChild(this.menu.element); + + this.input.addEventListener('keyup', this.onInputChange, false); + this.fieldChanged = createEvent('DirectoryField.fieldChanged'); + + // i.e. Register this.onItemClick as the default action for a menu click + this.menu.onItemClick = this.onItemClick.bind(this); + } + + DirectoryField.prototype = Object.create(Field.prototype); + + DirectoryField.prototype.destroy = function() { + Field.prototype.destroy.call(this); + this.input.removeEventListener('keyup', this.onInputChange, false); + this.menu.destroy(); + delete this.element; + delete this.input; + delete this.menu; + delete this.document; + delete this.onInputChange; + }; + + DirectoryField.prototype.setConversion = function(conversion) { + this.arg = conversion.arg; + this.input.value = conversion.arg.text; + this.setMessage(conversion.message); + + var items = []; + var predictions = conversion.getPredictions(); + predictions.forEach(function(item) { + // Commands can be hidden + if (!item.hidden) { + items.push({ + name: item.name, + complete: item.name, + description: ''//item.description || '' + }); + } + }, this); + this.menu.show(items); + + if (conversion.then) { // We only got a 'provisional' conversion. When caches are filled we'll get + // a callback and should try again. + var that = this; + conversion.then(function () { + if (that.element) { //if there's no UI yet => ignore. + that.setConversion(that.getConversion()); + } + }); + } + }; + + DirectoryField.prototype.onItemClick = function(ev) { + this.item = ev.currentTarget.item; + this.arg = this.arg.beget(this.item.complete, { normalize: true }); + var conversion = this.type.parse(this.arg); + this.fieldChanged({ conversion: conversion }); + this.setMessage(conversion.message); + }; + + DirectoryField.prototype.getConversion = function() { + // This tweaks the prefix/suffix of the argument to fit + this.arg = this.arg.beget(this.input.value, { prefixSpace: true }); + return this.type.parse(this.arg); + }; + + DirectoryField.claim = function(type) { + return type instanceof DirectoryType ? (Field.MATCH+1) : Field.NO_MATCH; + }; + + addField(DirectoryField); + + dojo.subscribe("/dojo/hashchange", function (newHash) { + cache = {}; + }); + + //Not exporting anything. This module just contributes stuff to gcli by calling gcli API. + return {}; +}); + + + diff --git a/bundles/org.eclipse.orion.client.console/web/console/gcliConsolePlugin.html b/bundles/org.eclipse.orion.client.console/web/console/gcliConsolePlugin.html new file mode 100644 index 0000000..6389368 --- a/dev/null +++ b/bundles/org.eclipse.orion.client.console/web/console/gcliConsolePlugin.html @@ -0,0 +1,31 @@ +<!DOCTYPE html> +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> + <script type="text/javascript" src="../orion/plugin.js"></script> + <script> + /*global window*/ + function qualifyURL(url){ + var a = document.createElement('a'); + a.href = url; // set string url + return a.href; + } + + window.onload = function() { + var serviceImpl = { /* All data is in properties */ }; + + var provider = new eclipse.PluginProvider(); + + provider.registerServiceProvider("orion.page.link", serviceImpl, { + name: "Console", + id: "orion.gcli", + uriTemplate: "{OrionHome}/console/orion-gcli-console.html" + }); + provider.connect(); + }; + </script> +</head> +<body> +<h1>Plugin</h1> +</body> +</html> diff --git a/bundles/org.eclipse.orion.client.console/web/console/orion-gcli-console.css b/bundles/org.eclipse.orion.client.console/web/console/orion-gcli-console.css new file mode 100644 index 0000000..d0e78e0 --- a/dev/null +++ b/bundles/org.eclipse.orion.client.console/web/console/orion-gcli-console.css @@ -0,0 +1,414 @@ +@import "../org.dojotoolkit/dojo/resources/dojo.css";
+
+@import "../org.dojotoolkit/dijit/themes/nihilo/nihilo.css";
+
+@import "../org.dojotoolkit/dijit/themes/nihilo/Tree.css";
+
+@import
+ "../org.dojotoolkit/dijit/themes/nihilo/layout/BorderContainer.css";
+
+@import "../org.dojotoolkit/dijit/themes/nihilo/form/Common.css";
+
+@import "../org.dojotoolkit/dijit/themes/nihilo/form/Button.css";
+
+@import "../css/ide.css";
+
+@import "../css/breadcrumbs.css";
+
+@import "../css/commands.css";
+
+@import "../org.dojotoolkit/dojox/grid/resources/Grid.css";
+
+@import "../org.dojotoolkit/dojox/grid/resources/nihiloGrid.css";
+
+html,body {
+ height: 100%;
+}
+
+h1 {
+ position: relative;
+ margin-top: 18px;
+}
+
+select {
+ font-size: 1em;
+ border: 1px #999 solid;
+ color: #666;
+}
+
+button {
+ background: white;
+ color: #666;
+ border: solid 1px #999;
+ border-radius: 2px;
+ font-size: 0.9em;
+}
+
+#pluginUrlEntry {
+ background: white;
+ color: #666;
+ border: solid 1px #999;
+ border-radius: 2px;
+ font-size: 0.9em;
+ padding: 1px;
+}
+
+.statusPane {
+ font-weight: bold;
+}
+
+.categories {
+ background: #EDEDED;
+}
+
+#content-title {
+ font-size: 1.2em;
+ font-weight: bold;
+ color: #666;
+ margin: 0;
+ padding-bottom: 14px;
+ padding-top: 13px;
+ margin-right: 16px;
+ text-align: right;
+}
+
+#categories>ul {
+ list-style-type: none;
+ margin: 0;
+ padding: 0;
+}
+
+#navbar {
+ margin: 0;
+ padding: 0;
+}
+
+.navbar-item {
+ border-bottom: 1px solid transparent;
+ border-top: 1px solid transparent;
+ color: #666;
+ display: block;
+ font-size: 90%;
+ outline: none;
+ padding: 7px 0;
+ text-align: right;
+ padding-right: 20px;
+ cursor:pointer;
+}
+
+ul,menu,dir {
+ display: block;
+ list-style-type: disc;
+}
+
+.navbar-item-selected {
+ background: #e3e3e3;
+ color: black;
+}
+
+.settings {
+ min-width:1000px;
+ max-width:1300px;
+ padding-left: 20px;
+ padding-right: 40px;
+}
+
+.pluginwrapper {
+ padding-bottom: 40px;
+ padding-top: 24px;
+ border-bottom: 1px dotted #BFBFBF;
+}
+
+.pluginTitle {
+ float: left;
+ font-size: 1.2em;
+ font-weight: bold;
+ color: #666;
+ margin: 0;
+}
+
+.oldLink {
+ float: left;
+ color: #666;
+ margin: 2px;
+ padding-left: 5px;
+}
+
+.sectionProgress {
+ float: left; font-size : 1.2em; font-weight : bold; color : #666;
+ margin-left: 2px;
+ text-decoration: blink;
+ font-size: 1.2em;
+ font-weight: bold;
+ color: #666;
+}
+
+.pluginSubTitle {
+ font-size: 1.1em;
+ font-weight: normal;
+ color: #666;
+ padding: 5px;
+}
+
+.additions {
+ float: right;
+ background: #666;
+ font-size: .9em;
+ color: white;
+ padding: 4px;
+ border-radius: 2px;
+}
+
+.additions-light {
+ float: right;
+ font-size: .9em;
+ color: white;
+ padding: 4px;
+ border-radius: 2px;
+}
+
+.settings h1 {
+ font-size: 1.2em;
+ font-weight: bold;
+ color: #666;
+ margin: 0;
+ padding-bottom: 14px;
+ padding-top: 13px;
+ border-bottom: 1px dotted #BFBFBF;
+}
+
+.settings section {
+ color: #666;
+ border-bottom: 1px dotted #BFBFBF;
+ display: -webkit-box;
+ display: -moz-box;
+ margin-top: 17px;
+ padding-bottom: 20px;
+ width: 100%;
+ margin-right: 16px;
+}
+
+.settings section>h3 {
+ margin: 0;
+ vertical-align: middle;
+ width: 130px;
+ padding-right: 10px;
+}
+
+.settings section>div {
+ margin: 0;
+ vertical-align: middle;
+}
+
+.settings section>div>div {
+ margin: 10px 0;
+}
+
+.settings section>div>div>label>span {
+ min-width: 145px;
+ display: inline-block;
+ min-width: 100px;
+}
+
+.displaytable>section {
+ display: table-row;
+}
+
+.web-content-select-label {
+ min-width: 145px;
+}
+
+.web-content-select-label>span:only-of-type {
+ display: inline-block;
+ min-width: 100px;
+}
+
+input[type="checkbox"] {
+ margin: 3px 3px 3px 4px;
+ margin-left: 0;
+ margin-right: 0;
+ position: relative;
+ top: 1px;
+}
+
+.addPluginClosed {
+ float: right;
+ width: 10px;
+ height: 10px;
+ background: #FEFF66;
+ background: #666;
+ padding: 4px;
+ color: white;
+ font-size: 8pt;
+ border-radius: 4px;
+ top: 10px;
+}
+
+.interactionOpen {
+ border-bottom: 1px dotted #BFBFBF;
+ height: 30px;
+ padding-bottom: 5px;
+ padding-top: 5px;
+ margin-right: 16px;
+ -webkit-padding-start: 5px;
+ -webkit-padding-end: 4px;
+ -webkit-transition: padding 500ms, height 400ms, opacity 800ms;
+ -moz-padding-start: 4px;
+ -moz-padding-end: 3px;
+ -moz-transition: padding 500ms, height 400ms, opacity 800ms;
+ -ms-padding-start: 4px;
+ -ms-padding-end: 3px;
+ -ms-transition: padding 500ms, height 400ms, opacity 800ms;
+}
+
+.interactionClosed {
+ height: 0;
+ opacity: 0;
+ margin-right: 16px;
+ -webkit-padding-start: 4px;
+ -webkit-padding-end: 3px;
+ -webkit-transition: padding 300ms, height 700ms, opacity 200ms;
+ -moz-padding-start: 4px;
+ -moz-padding-end: 3px;
+ -moz-transition: padding 300ms, height 700ms, opacity 200ms;
+ -ms-padding-start: 4px;
+ -ms-padding-end: 3px;
+ -ms-transition: padding 500ms, height 400ms, opacity 800ms;
+}
+
+#plugin-settings .displaytable>section {
+ display: block;
+ width: 100%;
+}
+
+div.page section:last-child {
+ border-bottom: none;
+}
+
+#plugin-settings .displaytable>section>* {
+ display: block;
+}
+
+#plugin-settings-list {
+ min-height: 0;
+ overflow-y: hidden;
+ width: 100%;
+}
+
+.plugin-list-item {
+ padding-top: 20px;
+ margin-bottom: 20px;
+ width: 100%;
+}
+
+list,grid {
+ display: block;
+ outline: none;
+ overflow: auto;
+ position: relative;
+}
+
+.plugin-icon {
+ float: left;
+ position: relative;
+ height: 48px;
+ vertical-align: text-top;
+ width: 48px;
+ padding-right: 15px;
+}
+
+.stretch {
+ float: left;
+ position: relative;
+ white-space:normal;
+ max-width:600px;
+}
+
+list>*,grid>* {
+ display: block;
+ outline: none;
+ overflow: auto;
+ position: relative;
+ line-height: 20px;
+ white-space: pre;
+}
+
+.plugin-title {
+ font-size: 16px;
+ font-weight: 500;
+ padding-right: 20px;
+}
+
+#plugin-settings .displaytable {
+ display: block;
+}
+
+.plugin-settings-content {
+ border-bottom: 0px solid #eee;
+ margin-top: 3px;
+ width: 100%;
+}
+
+.plugin-settings {
+ overflow-x: hidden;
+}
+
+.plugin-version {
+ font-size: 13px;
+ font-weight: 400;
+ padding-right: 10px;
+}
+
+.plugin-description {
+ font-size: 13px;
+ white-space: normal;
+ padding-right: 10px;
+ min-width:100px;
+ max-width:200px;
+}
+
+.plugin-delete {
+ float: right;
+ position: relative;
+ background: white;
+ color: #666;
+ border: solid 1px #999;
+ border-radius: 2px;
+ font-size: 0.9em;
+}
+
+.plugin-action-area {
+ float: right;
+ position: relative;
+ background: white;
+ color: #666;
+ font-size: 0.9em;
+}
+
+.plugin-links-view {
+ padding-right: 15px;
+}
+
+.plugin-links {
+ padding-right: 13px;
+}
+#gcli-row-complete {
+ position: absolute;
+ top: 2px;
+ left: 0;
+ width: 100%;
+ height: 20px;
+ font-family: "Courier New", "Lucida Console", monospace;
+ font-size: 13px;
+ z-index: -1000;
+}
+#gcli-input {
+ width: 100%;
+ padding-left: 1em;
+ font-family: "Courier New","Lucida Console",monospace;
+ font-size: 13px;
+ background: transparent;
+}
+#gcli-display {
+ overflow: hidden;
+}
\ No newline at end of file diff --git a/bundles/org.eclipse.orion.client.console/web/console/orion-gcli-console.html b/bundles/org.eclipse.orion.client.console/web/console/orion-gcli-console.html new file mode 100644 index 0000000..b91aa3d --- a/dev/null +++ b/bundles/org.eclipse.orion.client.console/web/console/orion-gcli-console.html @@ -0,0 +1,43 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="UTF-8"> + <title>Console</title> + + <link rel="stylesheet" type="text/css" href="orion-gcli-console.css" /> + <script type="text/javascript" src="../requirejs/require.js"></script> + <script type="text/javascript"> + + require({ baseUrl: '..', + packages: [{ name: 'dojo', location: 'org.dojotoolkit/dojo', main: 'lib/main-browser', lib: '.' }, + { name: 'dijit', location: 'org.dojotoolkit/dijit', main: 'lib/main',lib: '.' }, + { name: 'dojox', location: 'org.dojotoolkit/dojox', main: 'lib/main', lib: '.' } ], + paths: { text: 'requirejs/text', i18n: 'requirejs/i18n', domReady: 'requirejs/domReady' }, + packagePaths: { + "console/gcli/lib": [ + { name: "gcli", main: "index", lib: "." } +// { name: "test", main: "index", lib: "." }, +// { name: "gclitest", main: "index", lib: "." }, +// { name: "demo", main: "index", lib: "." } + ] + } + }); + require(["console/orion-gcli-console"]); + </script> + <body style="visibility:hidden" class="nihilo"> + <div id="orion.console" class="orionPage" dojoType="dijit.layout.BorderContainer" design="headline" gutters="false"> + <div class="banner" id="banner" dojoType="dijit.layout.ContentPane" region="top"> + </div> + <div id="centerPane" dojoType="dijit.layout.BorderContainer" region="center" gutters="false" design="headline" liveSplitters="false" splitter="false"> + <div class="toolbar" id="pageToolbar" dojoType="dijit.layout.ContentPane" splitter="false" region="top"> + </div> + <div id="gcli-display" dojoType="dijit.layout.ContentPane" region="center"></div> + <div id="glci-input-area" dojoType="dijit.layout.ContentPane" region="bottom"> + <input id="gcli-input"/> + <div id="gcli-row-complete"></div> + </div> + </div> + <div class="footer" id="footer" dojoType="dijit.layout.ContentPane" region="bottom" splitter="false"> + </div> + </body> +</html>
\ No newline at end of file diff --git a/bundles/org.eclipse.orion.client.console/web/console/orion-gcli-console.js b/bundles/org.eclipse.orion.client.console/web/console/orion-gcli-console.js new file mode 100644 index 0000000..7f8b858 --- a/dev/null +++ b/bundles/org.eclipse.orion.client.console/web/console/orion-gcli-console.js @@ -0,0 +1,284 @@ +/******************************************************************************* + * @license + * Copyright (c) 2011 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution + * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). + * + * Contributors: + * Contributors: IBM Corporation - initial API and implementation + * (copied: see explorer-table.js) + * Kris De Volder (VMWare) - Copied from explorer-table.js and modified to + * implement console page. + *******************************************************************************/ +/*global define require dojo dijit orion window widgets localStorage*/ +/*jslint browser:true devel:true*/ + +define(['dojo', 'orion/bootstrap', 'orion/status', 'orion/commands', 'orion/globalCommands', + 'orion/searchClient', 'orion/fileClient', 'gcli/index', 'console/directory-type', + 'console/current-directory', 'orion/es5shim'], +function(dojo, mBootstrap, mStatus, mCommands, mGlobalCommands, mSearchClient, mFileClient, gcli ) { + + var withWorkspace = require('console/current-directory').withWorkspace; + var withCurrentTreeNode = require('console/current-directory').withCurrentTreeNode; + var withChildren = require('console/current-directory').withChildren; + var setCurrentTreeNode = require('console/current-directory').setCurrentTreeNode; + var getParentLocation = require('console/current-directory').getParentLocation; + + var statusService; + + ////////////////// implementation of the ls command //////////////////////////////////////////////////////////// + + function editURL(node) { + //TODO: We should do this the right way. Orion probably has some + // service registration points to determine 'edit' actions based on the resource type. + // The only (bad) reason for this hacky implementation is that I do not yet know how to do + // it correctly. + return "/edit/edit.html#"+node.Location; + } + + /** + * Helper function to format a single child node in a directory. + */ + function formatLsChild(node, result) { + result = result || []; + if (node.Name) { + if (node.Directory) { + result.push(node.Name); + result.push('/'); + } else { + result.push('<a href="'); + result.push(editURL(node)); + result.push('">'); + result.push(node.Name); //TODO: html escape sequences? + result.push('</a>'); + } + result.push('<br>'); + } + return result; + } + + /** + * Helper function to format the result of ls. Accepts a current file or workspace node and + * formats its children. + * <p> + * Optionally accepts an array 'result' to which the resulting Strings should be pushed. + * <p> + * To avoid massive String copying the result is returned as an array of + * Strings rather than one massive String. Caller should join('') the returned result. + */ + function formatLs(node, result, k) { + result = result || []; + withChildren(node, function (children) { + for (var i = 0; i < children.length; i++) { + formatLsChild(children[i], result); + } + k(result); + }); + } + + /** + * Execution function for the ls gcli command + */ + function lsExec(args, context) { + var result = context.createPromise(); + setCurrentTreeNode(null); // Flushes current node cache. + withCurrentTreeNode(function (node) { + formatLs(node, [], function (buffer) { + result.resolve(buffer.join('')); + }); + }); + return result; + } + + ////////// implementaton of the 'cd' command /////////////////////////////////////////////////// + + function cdExec(args, context) { + var targetDirName = args.directory; + var result = context.createPromise(); + withCurrentTreeNode(function (node) { + if (targetDirName==='..') { + var newLocation = getParentLocation(node); + if (newLocation!==null) { + dojo.hash(newLocation); + setCurrentTreeNode(null); + result.resolve('Changed to parent directory'); + } else { + result.resolve('ERROR: Can not determine parent'); + } + } else { + withChildren(node, function (children) { + var found = false; + for (var i = 0; i < children.length; i++) { + var child = children[i]; + if (child.Name===targetDirName) { + if (child.Directory) { + found = true; + setCurrentTreeNode(child); + result.resolve('Working directory changed successfully'); + } else { + result.resolve('ERROR: '+targetDirName+' is not a directory'); + } + } + } + if (!found) { + result.resolve('ERROR: '+targetDirName+' not found.'); + } + }); + } + }); + return result; + } + + //////// implementation of the 'pwd' command /////////////////////////////////////////// + + function pwdExec(args, context) { + //TODO: this implementation doesn't print the full path, only the name of the current + // directory node. + var result = context.createPromise(); + withCurrentTreeNode(function (node) { + var buffer = formatLsChild(node); + result.resolve(buffer.join('')); + }); + return result; + } + + /** + * Add generally useful commands related to file/dir navigation. + * These commands are directly contributed to gcli, not via the 'orion.console.command' + * extension point. + */ + function initGenericCommands() { + gcli.addCommand({ + name: 'ls', + description: 'Show a list of files at the current directory', + exec: lsExec, + returnType: 'string' + }); + gcli.addCommand({ + name: 'cd', + description: 'Change current directory', + exec: cdExec, + returnType: 'string', + params: [ + { + name: 'directory', + type: 'directory', + description: 'directory' + } + ] + }); + + gcli.addCommand({ + name: 'pwd', + description: 'Print current directory', + exec: pwdExec, + returnType: 'string' + }); + } + + function render(text) { +// var node = dojo.create("pre", {className: 'console-command-output'}); +// // setting textContent we don't need to worry about escaping stuff. +// node.textContent = text; +// return node; + var obj = JSON.parse(text); + for (var key in obj) { + var node = dojo.create(key, obj[key]); + // node.textContent = 'asdf'; + return node; + } + } + + /** + * This function creates a JSON object that contains bits of context information an + * external command may need access to to execute. + */ + function createPluginContext(gcliContext, k) { + withWorkspace(function (wsNode) { + withCurrentTreeNode(function (pwdNode) { + return k({ + location: pwdNode.Location, + workspaceLocation: wsNode.Location + }); + }); + }); + } + + /** + * Creates a gcli exec function wrapping a 'run' function contributed by + * a 'orion.console.command' service implementation. + */ + function contributedExecFunc(service) { + if (typeof(service.run)==='function') { + //TODO: we may support different styles of exec functions based on + // properties set in the service. For now we just have the one + // type that executes asynchronously and renders the result as 'pre' text. + return function (args, context) { + var promise = context.createPromise(); + createPluginContext(context, function (jsonContext) { + service.run(args, jsonContext).then(function (result) { + promise.resolve(render(result)); + }); + }); + return promise; + }; + } + return undefined; + //returns undefined if we can't create an exec function (typically because the + //service doesn't provide one and is just a parent node in the command hierarchy). + } + + /** + * Wrap command implementations contributed via 'orion.console.command' extension + * point, and register them with gcli. + */ + function initContributedCommands(serviceRegistry) { + var allReferences = serviceRegistry.getServiceReferences("orion.console.command"); + for (var i = 0; i < allReferences.length; ++i) { + var ref = allReferences[i]; + var service = serviceRegistry.getService(ref); + if (service) { + gcli.addCommand({ + name: ref.getProperty("name"), + description: ref.getProperty("description"), + manual: ref.getProperty("manual"), + params: ref.getProperty("params"), + exec: contributedExecFunc(service) + }); + } + } + } + + //////////////////////////////////////////////////////////////////////// + + function initCommands(serviceRegistry) { + initGenericCommands(); + initContributedCommands(serviceRegistry); + } + + //TODO: Do we really need to wait for both dojo.ready and mBootstrap.startup? + // Maybe one of them already implies the other? + dojo.ready(function() { + mBootstrap.startup().then(function(core) { + + var serviceRegistry = core.serviceRegistry; + var preferences = core.preferences; + + document.body.style.visibility = "visible"; + dojo.parser.parse(); + + // Register services + statusService = new mStatus.StatusReportingService(serviceRegistry, "statusPane", "notifications"); + var commandService = new mCommands.CommandService({serviceRegistry: serviceRegistry}); + var searcher = new mSearchClient.Searcher({serviceRegistry: serviceRegistry, commandService: commandService, fileService: mFileClient}); + mGlobalCommands.generateBanner("banner", serviceRegistry, commandService, preferences, searcher); + + statusService.setMessage("Loading..."); + + initCommands(serviceRegistry); + gcli.createView(); + }); + }); +});
\ No newline at end of file |

