From b89a7ee8b956c96a1dcee995ea840feddc5d4b27 Mon Sep 17 00:00:00 2001 From: Pierre Frisch Date: Thu, 22 Dec 2011 07:25:50 -0800 Subject: First commit of Ninja to ninja-internal Signed-off-by: Valerio Virgillito --- js/io/system/config.xml | 6 + js/io/system/fileio.js | 226 +++++++++++++ js/io/system/filesystem.js | 723 ++++++++++++++++++++++++++++++++++++++++ js/io/system/projectio.js | 63 ++++ js/io/system/shellapi.js | 806 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 1824 insertions(+) create mode 100644 js/io/system/config.xml create mode 100644 js/io/system/fileio.js create mode 100644 js/io/system/filesystem.js create mode 100644 js/io/system/projectio.js create mode 100644 js/io/system/shellapi.js (limited to 'js/io/system') diff --git a/js/io/system/config.xml b/js/io/system/config.xml new file mode 100644 index 00000000..4660d647 --- /dev/null +++ b/js/io/system/config.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/js/io/system/fileio.js b/js/io/system/fileio.js new file mode 100644 index 00000000..1d76a91b --- /dev/null +++ b/js/io/system/fileio.js @@ -0,0 +1,226 @@ +/* +This file contains proprietary software owned by Motorola Mobility, Inc.
+No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + +//Required modules +var Serializer = require("montage/core/serializer").Serializer; +//Exporting as File I/O +exports.FileIo = (require("montage/core/core").Montage).create(Object.prototype, { + /* +create: { + enumerable: true, + value: function (type) { + // + } + }, +*/ + //////////////////////////////////////////////////////////////////// + // + open: { + enumerable: true, + value: function(doc, type, uri, server) { + // + var file = {}, head, body, h, b; + file.uri = uri; + file.server = server; + // + if (doc.content) { + if (type === 'html' || type === 'htm') { + // + h = doc.content.split(''); + h = h[0].split(''); + head = h[1]; + // + b = doc.content.split(''); + b = b[0].split(''); + body = b[1]; + // + file.type = 'html'; + file.head = head; + file.body = body; + } else { + //TODO: Add other file type routines + file.type = type; + file.content = doc.content; + } + } else { + //TODO: File is empty + if (type === 'html' || type === 'htm') { + head = ''; + body = ''; + // + file.type = 'html'; + file.head = head; + file.body = body; + } else { + //TODO: Add other file type routines + file.type = type; + file.content = doc.content; + } + } + //TODO: Load contents into App + //documentManagerModule.DocumentManager.openDocument(file); + } + }, + //////////////////////////////////////////////////////////////////// + // + save: { + enumerable: true, + value: function(type, id, components) { + + /* + + GETS HTML IN LOADED DOCUMENT + document.getElementById('userDocument').contentDocument.documentElement.outerHTML + + GETS HTML IN AND OR ANYTHING INSIDE + document.getElementById('userDocument').contentDocument.documentElement.innerHTML + + THE ABOVE METHOD SEEMS TO BE BETTER JUST IN CASE PEOPLE REMOVE THE BODY TAG SINCE NOT REQUIRED IN HTML5 + + GETS HTML IN ONLY + document.getElementById('userDocument').contentDocument.body.innerHTML + + HACK TO GET THE STYLES OF THE ELEMENTS ADDED WHILE DRAWING + document.getElementById('userDocument').contentDocument.styleSheets[document.getElementById('userDocument').contentDocument.styleSheets.length-1] + + CSS SEEMS TO BE RESERVED WHEN APPENDED, MEANING 0 IN THE ARRAY IS ACTUALLY THE LAST DEFINED STYLE IN THE CSS + + //GETS CSS RULES APPLIED TO ALL OBJECTS CREATED BY THE APP + document.getElementById('userDocument').contentDocument.styleSheets[document.getElementById('userDocument').contentDocument.styleSheets.length-1].cssRules + + document.getElementById('userDocument').contentDocument.getElementById('userHead').innerHTML + document.getElementById('userDocument').contentDocument.getElementById('UserContent').innerHTML + this.getCssFromRules(document.getElementById('userDocument').contentDocument.styleSheets[document.getElementById('userDocument').contentDocument.styleSheets.length-1].cssRules) + + */ + + // + var contents, counter = 0; + //Checking for document type to go through saving routine + switch (type.toLowerCase()) { + case 'html': + //Checking for components in components panel + if (components) { + var comps = '', comp, html, mbind, hackParams = '', compSerializer = Serializer.create(); + //TODO: Check if this is needed since compSerializer was localized + compSerializer._serializedObjects = []; + // + html = document.getElementById(id).contentDocument.getElementById('UserContent').innerHTML; + // + for(var i in components){ + // + comp = compSerializer.serializeObject(components[i]); + //TODO: Remove this HACK + if (components[i]._montage_metadata.__proto__.objectName == 'PhotoEditor') { + if (components[i].pathToJSON) { + hackParams = '"pathToJSON": "'+components[i].pathToJSON+'",\n'; + } + } else { + + } + var split = comp.split('"element":U("m-obj://undefined/'+components[i]._element.uuid); + comp = split[0]+hackParams+'\t"element":E("#'+components[i]._element.id+split[1]; + if (document.getElementById(id).contentDocument.getElementById(components[i]._originalElementId).innerHTML.length > 2) { + split = html.split(document.getElementById(id).contentDocument.getElementById(components[i]._originalElementId).innerHTML); + html = split[0]+split[1]; + } + // + if (counter > 0) { + comps += ',\n'+comp; + } else { + comps += comp; + } + counter++; + } + + for(var i in components){ + // + if (components[i]._bindingDescriptors){ + var split = comps.split('U("m-obj://undefined/'+components[i]._bindingDescriptors.uuid+'", {\n })'); + comps = split[0]+'\n'+ + '{\n'+ + '"'+components[i].binding.sourceProperty+'": {\n'+ + '"boundObject": U("m-obj://'+components[i].binding.target._montage_metadata.__proto__.objectName+'/'+components[i].binding.target.uuid+'?mId='+components[i].binding.target._montage_metadata.__proto__.moduleId+'"),\n'+ + '"boundObjectPropertyPath": "'+components[i].binding.targetProperty+'"\n'+ + '}\n'+ + '}\n'+ + split[1]; + } + } + var montage = ''; + + contents = '\n\t'+document.getElementById(id).contentDocument.getElementById('userHead').innerHTML+'\n\t\t'+montage+'\n\t\n\t\n'+html+'\n\t\n'; + } else { + //No m-js components in file, so saving plain document HTML + contents = '\n\t'+document.getElementById(id).contentDocument.getElementById('userHead').innerHTML+'\n\t\n\t\n'+document.getElementById(id).contentDocument.getElementById('UserContent').innerHTML+'\n\t\n'; + } + break; + case 'css': + contents = this.getCssFromRules(document.getElementById(id).contentDocument.styleSheets[document.getElementById(id).contentDocument.styleSheets.length-1].cssRules); + break; + case 'js': + break; + case 'text': + break; + default: + break; + } + + + return contents; + + + + } + }, + //////////////////////////////////////////////////////////////////// + // + saveAs: { + enumerable: true, + value: function(e) { + //TODO: Add functionality + console.log('FileIO: saveFileAs'); + } + }, + + + + + //////////////////////////////////////////////////////////////////// + //Method to return a string from CSS rules (to be saved to a file) + getCssFromRules: { + enumerable: false, + value: function (list) { + //Variable to store CSS definitions + var i, str, css = ''; + //Looping through list + if (list && list.length > 0) { + //Adding each list item to string and also adding breaks + for (i = 0; list[i]; i++) { + str = list[i].cssText+' '; + str = str.replace( new RegExp( "{", "gi" ), "{\n\t" ); + str = str.replace( new RegExp( "}", "gi" ), "}\n" ); + str = str.replace( new RegExp( ";", "gi" ), ";\n\t" ); + css += '\n'+str; + } + } + //Returning the CSS string + return css; + } + } + + + + + //////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////// +}); +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/js/io/system/filesystem.js b/js/io/system/filesystem.js new file mode 100644 index 00000000..54c16a05 --- /dev/null +++ b/js/io/system/filesystem.js @@ -0,0 +1,723 @@ +/* +This file contains proprietary software owned by Motorola Mobility, Inc.
+No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + +var FileIo = require("js/io/system/fileio").FileIo, + ProjectIo = require("js/io/system/projectio").ProjectIo, + ShellApi = require("js/io/system/shellapi").ShellApi, + ComponentsPanelBase = require("js/panels/Components/ComponentsPanelBase.reel").ComponentsPanelBase; +//////////////////////////////////////////////////////////////////////// +//Exporting as File System +exports.FileSystem = (require("montage/core/core").Montage).create(Object.prototype, { + //////////////////////////////////////////////////////////////////// + // + init: { + enumerable: false, + value: function () { + //Called by NinjaMain + + + + //Calling Shell API to initialize + ShellApi.init(); + } + }, + + shellApiHandler :{ + enumerable:true, + writable:false, + value:ShellApi + }, + + + //////////////////////////////////////////////////////////////////// + // + cloud: { + enumerable: false, + value: false + }, + //////////////////////////////////////////////////////////////////// + // + cloud: { + enumerable: false, + get: function() { + return this._cloud; + }, + set: function(value) { + this._cloud = value + } + }, + + + + + + + //////////////////////////////////////////////////////////////////// + // + _documentType: { + enumerable: false, + value: function () { + //return DocumentManagerModule.DocumentManager.activeDocument.documentType; // this._documentType() + } + }, + + + + //////////////////////////////////////////////////////////////////// + // + newFile: { + enumerable: false, + value: function (template) { + //Checking for cloud (to be added later) + if (this.cloud) { + //TODO: Add cloud integration + console.log("[CLOUD] New File"); + //documentManagerModule.DocumentManager.openDocument({"type": "html"}); + } else { + // + var file = {uri: ShellApi.openShellDialog({type: 'file', action: 'new'})}, type; + var check = ShellApi.fileExists(file); + + + + + + + + + + + + + + + //TODO: implement createFile to avoid duplicate funtionality + if (check.success) { + switch (check.status) { + case 204: + //TODO: Add logic for already existing file + window.alert('Error Code 204: File already exists.'); + break; + case 404: + //File does not exists, ready to be created + + + //TODO: The type (template) should be sent into this routine via the UI of file I/O (not by file extension as now) + if (template) { + type = template; + } else { + type = file.uri.split('.'); + type = type[type.length-1]; + } + // + + + //TODO: Improve logic + //Checking for file to exist in files template folder + var templateCheck = ShellApi.fileExists({uri: window.NativeShellApp.GetKnownFolder('appsource')+'\\document-templates\\files\\template.'+type}), content; + // + if (templateCheck.success) { + switch (check.status) { + case 204: + //Template exists, so opening and getting contents to be used when creating file + content = ShellApi.openFile({uri: 'template.'+type}); + if (content.content) { + file.content = content.content; + } else { + file.content = ""; + } + break; + case 404: + //No template + file.content = ""; + break; + case 500: + //Error + break; + default: + //Error + break; + } + } else { + + } + + + /* +switch (type.toLowerCase()) { + case 'html': + break; + case 'css': + break; + case 'js': + break; + case 'xml': + break; + case 'json': + break; + default: + break; + } +*/ + + + + + + + + var create = ShellApi.createFile(file); + if (create.success) { + switch (create.status) { + case 201: + //File was created, opening created file + this.openFile(file); + break; + case 400: + //TODO: Add error handling + //window.alert('Error Code 400: File already exists.'); + break; + case 500: + //TODO: Add error handling + //window.alert('Error Code 500: An error occurred while creating a new file.'); + break; + default: + //TODO: Add error handling + //window.alert('Unknown Error: An error occurred while creating a new file.'); + break; + } + } else { + //window.alert('Unknown Error: An error occurred while creating a new file.'); + } + + + + + + + + + + + + + break; + case 500: + //TODO: Add error handling + //window.alert('Error Code 500: An error occurred while creating a new file.'); + break; + default: + //TODO: Add error handling + //window.alert('Unknown Error: An error occurred while creating a new file.'); + break; + } + } else { + //TODO: Add error handling + //window.alert('Unknown Error: An error occurred while creating a new file.'); + } + } + + } + }, + + + + + + //////////////////////////////////////////////////////////////////// + // + newProject: { + enumerable: false, + value: function () { + //Checking for cloud (to be added later) + if (this.cloud) { + //TODO: Add cloud integration + console.log("[CLOUD] : New Project"); + //documentManagerModule.DocumentManager.openDocument({"type": "html"}); + } else { + // + var directory = {uri: ShellApi.openShellDialog({type: 'directory', action: 'new'})}; + var check = ShellApi.directoryExists(directory); + // + if (check.success) { + switch (check.status) { + case 204: + this.createProject(directory); + break; + case 404: + //Directory does not exists, ready to be created + var create = ShellApi.createDirectory(directory); + if (create.success) { + switch (create.status) { + case 201: + this.createProject(directory); + break; + case 400: + window.alert('Error Code 400: Directory already exists.'); + break; + case 500: + window.alert('Error Code 500: An error occurred while creating a new directory.'); + break; + default: + window.alert('Unknown Error: An error occurred while creating a new directory.'); + break; + } + } else { + window.alert('Unknown Error: An error occurred while creating a new directory.'); + } + break; + case 500: + //TODO: Add error handling + window.alert('Error Code 500: An error occurred while creating a new directory.'); + break; + default: + //TODO: Add error handling + window.alert('Unknown Error: An error occurred while creating a new directory.'); + break; + } + } else { + //TODO: Add error handling + window.alert('Unknown Error: An error occurred while creating a new directory.'); + } + } + } + }, + + + + //////////////////////////////////////////////////////////////////// + // + createFile: { + enumerable: false, + value: function (file) { + //Checking for file to exist + var check = ShellApi.fileExists(file), createdFile = null; + // + if (check.success) { + switch (check.status) { + case 204: + //TODO: Add logic for already existing file + break; + case 404: + //File does not exists, ready to be created + var create = ShellApi.createFile(file); + if (create.success) { + switch (create.status) { + case 201: + //File was created + createdFile = file; + break; + case 400: + //File already exists + createdFile = file; + break; + case 500: + //Error while creating + break; + default: + //TODO: Add error handling + break; + } + } else { + //Error creating file via API + } + break; + case 500: + //TODO: Add error handling + break; + default: + //TODO: Add error handling + break; + } + } else { + //TODO: Add error handling + } + // + return createdFile; + } + }, + + + + //////////////////////////////////////////////////////////////////// + // + openFile: { + enumerable: false, + value: function (file) { + var uri, i; + //Checking for file to defined (otherwise prompts for URI) + if (file && file.uri) { + uri = file.uri; + } else { + //Checking to prompt user depending on mode + if (this.cloud) { + //TODO: Add cloud integration + } else { + //Getting file URI from native prompt + uri = ShellApi.openShellDialog({type: 'file', action: 'open'}); + } + } + //Checking for a valid URI + if (uri && uri.length>0) { + //Checking for URI to be single or array of URIs + if (uri.constructor.toString().indexOf('Array') == -1) { + //Opening single URI + shellOpenFile(uri); + } else { + //Opening via loop of URIs + for (i=0; uri[i]; i++) { + shellOpenFile (uri[i]); + } + } + } else { + //No file was selected to be opened, nothing happens + } + //Opening file via shell + function shellOpenFile (f) { + //Getting string from file + var doc = ShellApi.openFile({uri: f}), type = f.split('.'); + //Splitting to get file extension + type = type[type.length-1]; + //TODO: Fix this HACK to generate string + var dir = f.split('\\'), dir_str = '', server; + for (var i=0; i < dir.length-1; i++) { + dir_str += dir[i] + '\\'; + } + //Starting an instance of the shell server on directory + server = ShellApi.startServer(dir_str); + //Opening file in app + FileIo.open(doc, type, f, server); + } + } + }, + + //////////////////////////////////////////////////////////////////// + //Creating unified method to check for success + //FOR: Move, Copy, Rename + directoryMCRCheck: { + enumerable: false, + value: function (r, code) { + //TODO: Add error handling for unsuccessful attempts + var outcome; + // + if (r.success) { + // + outcome = {}; + // + switch (r.status) { + case 204: + //Success + break; + case 400: + //Already exists + break; + case 404: + //Source does not exists + break; + case 500: + //Unknonwn + break; + default: + break; + } + } else { + //TODO: Add error handling + } + // + return outcome; + } + }, + + + //////////////////////////////////////////////////////////////////// + // + createProject: { + enumerable: false, + value: function (directory) { + var mjs_dir = {uri: directory.uri}; + mjs_dir.uri += '\\m-js'; + var mjs_check = ShellApi.directoryExists(mjs_dir); + // + if (mjs_check.success) { + switch (mjs_check.status) { + case 204: + //TODO: Add logic to check for the correct version of m-js + break; + case 404: + //m-js does not exists, ready to be created + + + + + + + //Creating m-js folder and copying contents + var mjs_folder = ShellApi.createDirectory(mjs_dir); + if (mjs_folder.success) { + switch (mjs_folder.status) { + case 201: + //TODO: Add error handling for error on copy sub directories + + + var temp_dir = window.NativeShellApp.GetKnownFolder('appsource')+'\\user-document-templates\\montage-application\\systemio\\new\\project\\montage'; + var mjs_deps = ShellApi.createDirectory({uri: mjs_dir.uri+'\\deps'}); + + //Folder created, now copying contents + var copy_lib = ShellApi.copyDirectory({sourceUri: window.NativeShellApp.GetKnownFolder('frameworksource')+'\\lib', destUri: mjs_dir.uri+'\\lib'}), + copy_deps = ShellApi.copyDirectory({sourceUri: window.NativeShellApp.GetKnownFolder('frameworksource')+'\\deps\\require', destUri: mjs_dir.uri+'\\deps\\require'}), + copy_components = ShellApi.copyDirectory({sourceUri: window.NativeShellApp.GetKnownFolder('appsource')+'\\montage-components', destUri: directory.uri+'\\montage-components'}); + + //Checking for lib operation's result + if (copy_lib.success) { + //Successful copy of directory + } else { + //Error, checking to see reason for error and this method should handling error state + var check_lib = this.directoryMCRCheck(copy_lib, true); + } + + //Checking for deps operation's result + if (copy_deps.success) { + //Successful copy of directory + } else { + //Error, checking to see reason for error and this method should handling error state + var check_deps = this.directoryMCRCheck(copy_deps, true); + } + + //Checking for components operation's result + if (copy_components.success) { + //Successful copy of directory + } else { + //Error, checking to see reason for error and this method should handling error state + var check_components = this.directoryMCRCheck(copy_components, true); + } + + var prj_tmplt = window.NativeShellApp.GetKnownFolder('appsource')+'\\document-templates\\projects\\montage'; + //TODO: Add error handling for file copying, clean up this HACK + var copy_packagemjs = ShellApi.copyFile({sourceUri: window.NativeShellApp.GetKnownFolder('frameworksource')+'\\package.json', destUri: mjs_dir.uri+'\\package.json'}), + copy_styles = ShellApi.copyFile({sourceUri: prj_tmplt+'\\styles.css', destUri: directory.uri+'\\styles.css'}), + copy_appdelegate = ShellApi.copyFile({sourceUri: prj_tmplt+'\\appdelegate.js', destUri: directory.uri+'\\appdelegate.js'}), + copy_package = ShellApi.copyFile({sourceUri: prj_tmplt+'\\package.json', destUri: directory.uri+'\\package.json'}), + copy_index = ShellApi.copyFile({sourceUri: prj_tmplt+'\\index.html', destUri: directory.uri+'\\index.html'}); + + // + this.openProject(directory); + + + + + break; + case 400: + //TODO: Add logic to handle already existing copy of m-js + break; + case 500: + //TODO: Add error handling + break; + default: + //TODO: Add error handling + break; + } + } else { + //TODO: Add error handling + } + + + + + + + + + break; + case 500: + //TODO: Add error handling + break; + default: + //TODO: Add error handling + break; + } + } else { + //TODO: Add error handling + } + } + }, + + + + //////////////////////////////////////////////////////////////////// + // + openProject: { + enumerable: false, + value: function (directory) { + //TODO: Add functionality, this is a HACK + + + + + + var uri, i; + //Checking for directory to defined (otherwise prompts for URI) + if (directory && directory.uri) { + uri = directory.uri; + } else { + //Checking to prompt user depending on mode + if (this.cloud) { + //TODO: Add cloud integration + } else { + //Getting file URI from native prompt + uri = ShellApi.openShellDialog({type: 'directory', action: 'open'}); + } + } + //Checking for a valid URI + if (uri && uri.length>0) { + + this.openFile({uri: uri+'\\index.html'}); + + + } else { + //No file was selected to be opened, nothing happens + } + + + + + + } + }, + + + + + + //////////////////////////////////////////////////////////////////// + // + saveFile: { + enumerable: false, + value: function (f) { + //console.log(f); + //TODO: Add functionality + //console.log('FileSystem: saveFile'); + //HACK + + //////////////////////////////////////////////////////////////////// + // DEBUG CODE TO TEST WebGL I/O + //var glData = DocumentManagerModule.DocumentManager.activeDocument.glData; + //DocumentManagerModule.DocumentManager.activeDocument.glData = glData; + //////////////////////////////////////////////////////////////////// + + if (f) { + var s = ShellApi.updateFile(f); + } else { + //HACK + this.saveProject(); + } + + } + }, + + + + + //////////////////////////////////////////////////////////////////// + // + saveFileAs: { + enumerable: false, + value: function () { + //TODO: Add functionality + //console.log('FileSystem: saveFileAs'); + //HACK + this.saveProject(); + } + }, + + + + + + //////////////////////////////////////////////////////////////////// + // + saveProject: { + enumerable: false, + value: function () { + //FileIo.save('project'); + //console.log(DocumentManagerModule.DocumentManager.activeDocument._userComponentSet); + //DocumentManagerModule.DocumentManager.activeDocument.server.root + + //////////////////////////////////////////////////////////////////// + // DEBUG CODE TO TEST WebGL I/O + //var glData = DocumentManagerModule.DocumentManager.activeDocument.glData; + //DocumentManagerModule.DocumentManager.activeDocument.glData = glData; + //////////////////////////////////////////////////////////////////// + +// var root = DocumentManagerModule.DocumentManager.activeDocument.server.root; +// +// // +// var project = ProjectIo.save('montageapp', +// DocumentManagerModule.DocumentManager.activeDocument.iframe.id, +// DocumentManagerModule.DocumentManager.activeDocument._userComponentSet); +// +// +// +// // +// var cssSave = this.saveFile({uri: root+'styles.css', contents: project.css}); +// var htmlSave = this.saveFile({uri: root+'index.html', contents: project.html}); + + } + }, + + + + + //////////////////////////////////////////////////////////////////// + // + saveAll: { + enumerable: false, + value: function () { + //TODO: Add functionality + //console.log('FileSystem: saveAll'); + //HACK + this.saveProject(); + } + }, + + + + + + //////////////////////////////////////////////////////////////////// + // + closeFile: { + enumerable: false, + value: function () { + //TODO: Add functionality + console.log('FileSystem: closeFile'); + } + }, + + + + + + //////////////////////////////////////////////////////////////////// + // + closeProject: { + enumerable: false, + value: function () { + //TODO: Add functionality + console.log('FileSystem: closeProject'); + } + } + + + + + + + + //////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////// +}); +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/js/io/system/projectio.js b/js/io/system/projectio.js new file mode 100644 index 00000000..822fd385 --- /dev/null +++ b/js/io/system/projectio.js @@ -0,0 +1,63 @@ +/* +This file contains proprietary software owned by Motorola Mobility, Inc.
+No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + +var FileIo = require("js/io/system/fileio").FileIo; +//////////////////////////////////////////////////////////////////////// +//Exporting as Project I/O +exports.ProjectIo = (require("montage/core/core").Montage).create(Object.prototype, { + //////////////////////////////////////////////////////////////////// + // + create: { + enumerable: false, + value: function () { + } + }, + //////////////////////////////////////////////////////////////////// + // + open: { + enumerable: false, + value: function(e) { + //TODO: Add functionality + console.log('ProjectIO: open'); + } + }, + //////////////////////////////////////////////////////////////////// + // + save: { + enumerable: false, + value: function(type, id, components) { + // + var rObj; + // + switch (type) { + case 'montageapp': + // + var css = FileIo.save('css', id); + var html = FileIo.save('html', id, components); + // + rObj = {html: html, css: css}; + break; + default: + break; + } + // + return rObj; + } + }, + //////////////////////////////////////////////////////////////////// + // + saveAs: { + enumerable: false, + value: function(e) { + //TODO: Add functionality + console.log('ProjectIO: saveAs'); + } + } + //////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////// +}); +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/js/io/system/shellapi.js b/js/io/system/shellapi.js new file mode 100644 index 00000000..9976dbed --- /dev/null +++ b/js/io/system/shellapi.js @@ -0,0 +1,806 @@ +/* +This file contains proprietary software owned by Motorola Mobility, Inc.
+No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + +/* ///////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +NOTES: All logic should be handled in the FileSystem and I/O classes + +Dialog methods on NativeShellApp +ShowFileOpenDialog(initialDir) - shows a file open dialog +initialDir is optional and if specified will cause the dialog to initially display that directory as the open location +ShowFileSaveAsDialog(initialURI) - shows a file Save As dialog +initialURI is optional and if specified will cause the dialog to initially display the directory as the default location +and the filename as the current filename. +ShowSelectDirectoryDialog(initialDir, dialogTitle) - displays a directory select/chooser dialog +intitalDir is optional and specifies the directory that should be selected/shown when the dialog opens +dialogTitle is optional and specifies the title that should appear in the dialog caption +//////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////// */ +//Exporting as Project I/O +exports.ShellApi = (require("montage/core/core").Montage).create(require("montage/ui/component").Component, { + //////////////////////////////////////////////////////////////////// + // + init: { + enumerable: false, + value: function() { + try { + var xhr = new XMLHttpRequest(), file, directory; + // + xhr.open("GET", 'cloud/config.xml', false); + xhr.send(); + // + if (xhr.readyState === 4) { + file = xhr.responseXML.getElementsByTagName('file')[0].firstChild.nodeValue; + directory = xhr.responseXML.getElementsByTagName('directory')[0].firstChild.nodeValue; + if (file.length) + this._fileServiceURL = file; + if (directory.length) + this._directoryServiceURL = directory; + // + //console.log(file, directory); + } + } + catch(error) { + console.log(error); + } + } + }, + //////////////////////////////////////////////////////////////////// + // + openShellDialog: { + enumerable: false, + value: function(dialog) { + //Initializing return variable + var input = null; + //Checking for the type of prompt set via object + switch (dialog.type) { + case 'file': + //Checking for action the prompt will ask the user + if (dialog.action.toLowerCase() == 'open') { + //File open dialog + input = window.NativeShellApp.ShowFileOpenDialog(); + } else if (dialog.action.toLowerCase() == 'new') { + //File new dialog + input = window.NativeShellApp.ShowFileSaveAsDialog(); + } + break; + case 'directory': + //Checking for action the prompt will ask the user + if (dialog.action.toLowerCase() == 'open') { + //Directory open dialog + input = window.NativeShellApp.ShowSelectDirectoryDialog(); + } else if (dialog.action.toLowerCase() == 'new') { + //Directory new dialog + input = window.NativeShellApp.ShowSelectDirectoryDialog(); + } + break; + break; + default: + break; + } + return input; + } + }, + //////////////////////////////////////////////////////////////////// + // + startServer: { + enumerable: false, + value: function (dir) { + var server = window.NativeShellApp.StartWebServer(dir); + return server; + } + }, + //////////////////////////////////////////////////////////////////// + // private property containing the file service URL to use for all file IO calls + _fileServiceURL: { + enumerable: false, + value: "http://localhost:16380/file" //default value.. updated with base uri in config.xml + }, + //////////////////////////////////////////////////////////////////// + // private property containing the directory service URL to use for all file IO calls + _directoryServiceURL: { + enumerable: false, + value: "http://localhost:16380/directory" //default value.. updated with base uri in config.xml + }, + //////////////////////////////////////////////////////////////////// + // private helper to parse URIs and append them to the service URL + _prepareServiceURL: { + enumerable: false, + value: function(serviceURL, path) { + var urlOut = path.replace(/\\/g,"/"); + urlOut = urlOut.replace(/:/g,""); + urlOut = encodeURI(urlOut); + //add leading / if not already there + if((urlOut.length > 0) && (urlOut.charAt(0) !== "/")){ + urlOut = "/" + urlOut; + } + return serviceURL + urlOut; + } + }, + //////////////////////////////////////////////////////////////////// + // Checks for the existence of a file + // Parameters: + // the file parameter must contain the following properties + // uri: string value containing the full file path/URI i.e. "c:/foo/bar.html" + // + // Return values: + // returns an object with two properties + // success: boolean indicating if the call succeeded or failed + // status: int indicating the request HTTP status code + // 204 - the file exists + // 404 - the file does not exist + // 500 - unknown server error occurred + fileExists: { + enumerable: false, + value: function(file) { + // + var retValue = { success:null, status:null }; + // + if(file && file.uri && file.uri.length) { + try { + var serviceURL = this._prepareServiceURL(this._fileServiceURL, file.uri), + xhr = new XMLHttpRequest(); + // + xhr.open("GET", serviceURL, false); + xhr.setRequestHeader("check-existence-only", "true"); + xhr.send(); + // + if (xhr.readyState === 4) { + retValue.status = xhr.status; + retValue.success = true; + } + } + catch(error) { + xhr = null; + retValue.success = false; + } + } + // + return retValue; + } + }, + //////////////////////////////////////////////////////////////////// + // Creates a new file at the specified path + // Parameters: + // the file parameter must contain the following properties + // uri: string value containing the full file path/URI i.e. "c:/foo/bar.html" + // it can optionally contain the following properties + // contentType: string with the content type i.e. "text/plain". "text/plain" is assumed if this property is not specified + // contents: string containing the file contents. These contents will be saved to the new file. + // + // Return values: + // returns an object with two properties + // success: boolean indicating if the call succeeded or failed + // status: int indicating the request HTTP status code + // 201 - the file was created and contents were saved if they were passed + // 400 - the file already exists and could not be created + // 500 - unknown server error occurred + createFile: { + enumerable: false, + value: function(file) { + var retValue = { success:null, status:null }; + if(file && file.uri && file.uri.length) { + try { + var serviceURL = this._prepareServiceURL(this._fileServiceURL, file.uri), + xhr = new XMLHttpRequest(); + // + xhr.open("POST", serviceURL, false); + if(file.contentType && file.contentType.length) + xhr.setRequestHeader("Content-Type", file.contentType); + else + xhr.setRequestHeader("Content-Type", "text/plain"); + + if(file.contents && file.contents.length) + xhr.send(file.contents); + else + xhr.send(); + + if (xhr.readyState === 4) { + retValue.status = xhr.status; + retValue.success = true; + } + } + catch(error) { + xhr = null; + retValue.success = false; + } + } + + return retValue; + } + }, + //////////////////////////////////////////////////////////////////// + // Save contents into an existing file at the specified path + // Parameters: + // the file parameter must contain the following properties + // uri: string value containing the full file path/URI i.e. "c:/foo/bar.html" + // it can optionally contain the following properties + // contentType: string with the content type i.e. "text/plain". "text/plain" is assumed if this property is not specified + // contents: string containing the file contents. These contents will be saved to the new file. + // + // Return values: + // returns an object with two properties + // success: boolean indicating if the call succeeded or failed + // status: int indicating the request HTTP status code + // 204 - the file was saved + // 404 - the file specified does not exist + // 500 - unknown server error occurred + updateFile: { + enumerable: false, + value: function(file) { + var retValue = { success:null, status:null }; + if(file && file.uri && file.uri.length && file.contents && file.contents.length) { + try { + var serviceURL = this._prepareServiceURL(this._fileServiceURL, file.uri), + xhr = new XMLHttpRequest(); + // + xhr.open("PUT", serviceURL, false); + if(file.contentType && file.contentType.length) + xhr.setRequestHeader("Content-Type", file.contentType); + else + xhr.setRequestHeader("Content-Type", "text/plain"); + + xhr.send(file.contents); + + if (xhr.readyState === 4) { + retValue.status = xhr.status; + retValue.success = true; + } + } + catch(error) { + xhr = null; + retValue.success = false; + } + } + + return retValue; + } + }, + //////////////////////////////////////////////////////////////////// + // Copies a file from one location to another + // Parameters: + // the file parameter must contain the following properties + // sourceUri: string value containing the full file path/URI to copy from i.e. "c:/foo/bar.html" + // destUri: string containing the full path/URI to copy to + // it can optionally contain the following properties + // overwriteDestination: bool indicating whether it is okay to overwrite the file specified at destUri if it already exists + // + // Return values: + // returns an object with two properties + // success: boolean indicating if the call succeeded or failed + // status: int indicating the request HTTP status code + // 204 - the file was copied + // 404 - the file specified in sourceUri does not exist + // 500 - unknown server error occurred + copyFile: { + enumerable: false, + value: function(file) { + var retValue = { success:null, status:null }; + if(file && file.sourceUri && file.sourceUri.length && file.destUri && file.destUri.length) { + try { + var serviceURL = this._prepareServiceURL(this._fileServiceURL, file.destUri), + xhr = new XMLHttpRequest(); + // + xhr.open("PUT", serviceURL, false); + xhr.setRequestHeader("sourceURI", file.sourceUri); + // + if(file.overwriteDestination && file.overwriteDestination === true) { + xhr.setRequestHeader("overwrite-destination", "true"); + } + // + xhr.send(); + // + if (xhr.readyState === 4) { + retValue.status = xhr.status; + retValue.success = true; + } + } + catch(error) { + xhr = null; + retValue.success = false; + } + } + // + return retValue; + } + }, + //////////////////////////////////////////////////////////////////// + // Moves a file from one location to another + // Parameters: + // the file parameter must contain the following properties + // sourceUri: string value containing the full file path/URI to copy from i.e. "c:/foo/bar.html" + // destUri: string containing the full path/URI to copy to + // it can optionally contain the following properties + // overwriteDestination: bool indicating whether it is okay to overwrite the file specified at destUri if it already exists + // + // Return values: + // returns an object with two properties + // success: boolean indicating if the call succeeded or failed + // status: int indicating the request HTTP status code + // 204 - the file was moved + // 404 - the file specified in sourceUri does not exist + // 500 - unknown server error occurred + moveFile: { + enumerable: false, + value: function(file) { + var retValue = { success:null, status:null }; + if(file && file.sourceUri && file.sourceUri.length && file.destUri && file.destUri.length) { + try { + var serviceURL = this._prepareServiceURL(this._fileServiceURL, file.destUri), + xhr = new XMLHttpRequest(); + // + xhr.open("PUT", serviceURL, false); + xhr.setRequestHeader("sourceURI", file.sourceUri); + xhr.setRequestHeader("delete-source", "true"); + // + if(file.overwriteDestination && file.overwriteDestination === true) { + xhr.setRequestHeader("overwrite-destination", "true"); + } + // + xhr.send(); + // + if (xhr.readyState === 4) { + retValue.status = xhr.status; + retValue.success = true; + } + } + catch(error) { + xhr = null; + retValue.success = false; + } + } + // + return retValue; + } + }, + //////////////////////////////////////////////////////////////////// + // Deletes an existing file + // Parameters: + // the file parameter must contain the following properties + // uri: string value containing the full file path/URI i.e. "c:/foo/bar.html" + // + // Return values: + // returns an object with two properties + // success: boolean indicating if the call succeeded or failed + // status: int indicating the request HTTP status code + // 204 - the file was deleted + // 404 - the file does not exist + // 500 - unknown server error occurred + deleteFile: { + enumerable: false, + value: function(file) { + var retValue = { success:null, status:null }; + if(file && file.uri && file.uri.length) { + try { + var serviceURL = this._prepareServiceURL(this._fileServiceURL, file.uri), + xhr = new XMLHttpRequest(); + // + xhr.open("DELETE", serviceURL, false); + xhr.send(); + // + if (xhr.readyState === 4) { + retValue.status = xhr.status; + retValue.success = true; + } + } + catch(error) { + xhr = null; + retValue.success = false; + } + } + // + return retValue; + } + }, + //////////////////////////////////////////////////////////////////// + // Reads an existing file + // Parameters: + // the file parameter must contain the following properties + // uri: string value containing the full file path/URI i.e. "c:/foo/bar.html" + // + // Return values: + // returns an object with two properties + // success: boolean indicating if the call succeeded or failed + // content: string containing the file contents + // status: int indicating the request HTTP status code + // 200 - the file was read and its contents were returned + // 404 - the file does not exist + // 500 - unknown server error occurred + openFile: { + enumerable: false, + value: function(file) { + // + var retValue = { success:null, content:null, status:null }; + // + if(file && file.uri && file.uri.length) { + try { + var serviceURL = this._prepareServiceURL(this._fileServiceURL, file.uri), + xhr = new XMLHttpRequest(); + // + xhr.open("GET", serviceURL, false); + xhr.send(); + // + if (xhr.readyState === 4) { + retValue.status = xhr.status; + if(xhr.status == 200) { + retValue.content = xhr.responseText; + } + retValue.success = true; + } + } + catch(error) { + xhr = null; + retValue.success = false; + } + } + // + return retValue; + } + }, + //////////////////////////////////////////////////////////////////// + // Create a new directory/folder + // Parameters: + // the dir parameter must contain the following properties + // uri: string value containing the full file path/URI i.e. "c:/dir/subdir" + // + // Return values: + // returns an object with two properties + // success: boolean indicating if the call succeeded or failed + // status: int indicating the request HTTP status code + // 201 - the directory was created + // 400 - the directory was unable to be created + // 500 - unknown server error occurred + createDirectory: { + enumerable: false, + value: function(dir) { + var retValue = { success:null, status:null }; + if(dir && dir.uri && dir.uri.length) { + try { + var serviceURL = this._prepareServiceURL(this._directoryServiceURL, dir.uri), + xhr = new XMLHttpRequest(); + // + xhr.open("POST", serviceURL, false); + xhr.send(); + // + if (xhr.readyState === 4) { + retValue.status = xhr.status; + retValue.success = true; + } + } + catch(error) { + xhr = null; + retValue.success = false; + } + } + // + return retValue; + } + }, + //////////////////////////////////////////////////////////////////// + // Delete a directory/folder + // Parameters: + // the dir parameter must contain the following properties + // uri: string value containing the full file path/URI i.e. "c:/dir/subdir" + // + // Return values: + // returns an object with two properties + // success: boolean indicating if the call succeeded or failed + // status: int indicating the request HTTP status code + // 204 - the directory was deleted + // 404 - the directory does not exist + // 500 - unknown server error occurred + deleteDirectory: { + enumerable: false, + value: function(dir) { + var retValue = { success:null, status:null }; + if(dir && dir.uri && dir.uri.length) { + try { + var serviceURL = this._prepareServiceURL(this._directoryServiceURL, dir.uri), + xhr = new XMLHttpRequest(); + // + xhr.open("DELETE", serviceURL, false); + xhr.send(); + // + if (xhr.readyState === 4) { + retValue.status = xhr.status; + retValue.success = true; + } + } + catch(error) { + xhr = null; + retValue.success = false; + } + } + // + return retValue; + } + }, + //////////////////////////////////////////////////////////////////// + // List the contents of a directory/folder + // Parameters: + // the dir parameter must contain the following properties + // uri: string value containing the full file path/URI i.e. "c:/dir/subdir" + // recursive: boolean true to list contents of all subdirectories as well. if this is not specified "false" is the default. + // returnType: string "all", "files", "directories". Specifies the types to return. if this is not specified, the default is "all" + // fileFilters: string containing the file extensions to include in the return listing. This list is semi-colon separated. i.e. "xml;html" + // + // Return values: + // returns an object with two properties + // success: boolean indicating if the call succeeded or failed + // content: string containing the JSON structure of the file contents + // status: int indicating the request HTTP status code + // 200 - the directory was read and the content JSON string was returned in dir.content + // 404 - the directory does not exist + // 500 - unknown server error occurred + getDirectoryContents: { + enumerable: false, + value: function(dir) { + var retValue = { success:null, content:null, status:null }; + if(!!dir && (typeof dir.uri !== "undefined") && (dir.uri !== null) ) { + try { + var serviceURL = this._prepareServiceURL(this._directoryServiceURL, dir.uri), + xhr = new XMLHttpRequest(); + // + xhr.open("GET", serviceURL, false); + // + if(dir.recursive) { + xhr.setRequestHeader("recursive", dir.recursive.toString()); + } + + // + if (dir.fileFilters) { + xhr.setRequestHeader("file-filters", dir.fileFilters.toString()); + } + // + + // + if(dir.returnType) { + xhr.setRequestHeader("return-type", dir.returnType.toString()); + } + // + xhr.send(); + // + if (xhr.readyState === 4) { + retValue.status = xhr.status; + if(xhr.status == 200) { + retValue.content = xhr.responseText; + } + retValue.success = true; + } + } + catch(error) { + xhr = null; + retValue.success = false; + } + } + // + return retValue; + } + }, + //////////////////////////////////////////////////////////////////// + // Check if a directory/folder exists + // Parameters: + // the dir parameter must contain the following properties + // uri: string value containing the full file path/URI i.e. "c:/dir/subdir" + // + // Return values: + // returns an object with two properties + // success: boolean indicating if the call succeeded or failed + // status: int indicating the request HTTP status code + // 204 - the directory exists + // 404 - the directory does not exist + // 500 - unknown server error occurred + directoryExists: { + enumerable: false, + value: function(dir) { + var retValue = { success:null, content:null, status:null }; + if(dir && dir.uri && dir.uri.length) { + try { + var serviceURL = this._prepareServiceURL(this._directoryServiceURL, dir.uri), + xhr = new XMLHttpRequest(); + // + xhr.open("GET", serviceURL, false); + xhr.setRequestHeader("check-existence-only", "true"); + // + xhr.send(); + // + if (xhr.readyState === 4) { + retValue.status = xhr.status; + retValue.success = true; + } + } + catch(error) { + xhr = null; + retValue.success = false; + } + } + // + return retValue; + } + }, + //////////////////////////////////////////////////////////////////// + // copies an existing directory/folder to a new location + // Parameters: + // the dir parameter must contain the following properties + // sourceUri: string value containing the full file path/URI to copy from i.e. "c:/foo/bar" + // destUri: string containing the full path/URI to copy to + // + // Return values: + // returns an object with two properties + // success: boolean indicating if the call succeeded or failed + // status: int indicating the request HTTP status code + // 204 - the operation succeeded + // 400 - the operation could not be performed because the destUri existed + // 404 - the source directory does not exist + // 500 - unknown server error occurred + copyDirectory: { + enumerable: false, + value: function(dir) { + return this._copyMoveDirHelper(dir.sourceUri, dir.destUri, "copy"); + } + }, + //////////////////////////////////////////////////////////////////// + // Moves an existing directory/folder to a new location + // Parameters: + // the dir parameter must contain the following properties + // sourceUri: string value containing the full file path/URI to copy from i.e. "c:/foo/bar" + // destUri: string containing the full path/URI to move to + // + // Return values: + // returns an object with two properties + // success: boolean indicating if the call succeeded or failed + // status: int indicating the request HTTP status code + // 204 - the operation succeeded + // 400 - the operation could not be performed because the destUri existed + // 404 - the source directory does not exist + // 500 - unknown server error occurred + moveDirectory: { + enumerable: false, + value: function(dir) { + return this._copyMoveDirHelper(dir.sourceUri, dir.destUri, "move"); + } + }, + //////////////////////////////////////////////////////////////////// + // Moves an existing directory/folder to a new location + // Parameters: + // the dir parameter must contain the following properties + // sourceUri: string value containing the full file path/URI to copy from i.e. "c:/foo/bar" + // newDirectoryName: string containing the new name of the directory i.e. "bar2" + // + // Return values: + // returns an object with two properties + // success: boolean indicating if the call succeeded or failed + // status: int indicating the request HTTP status code + // 204 - the operation succeeded + // 400 - the operation could not be performed because the destUri existed + // 404 - the source directory does not exist + // 500 - unknown server error occurred + renameDirectory: { + enumerable: false, + value: function(dir) { + return this._copyMoveDirHelper(dir.sourceUri, dir.sourceUri + "/" + dir.newDirectoryName, "move"); + } + }, + //////////////////////////////////////////////////////////////////// + //Helper that is used by copyDirectory, moveDirectory, renameDirectory + _copyMoveDirHelper: { + enumerable: false, + value: function(sourceDir, destDir, operation) { + var retValue = {}; + if(sourceDir && sourceDir.length && destDir && destDir.length && operation && operation.length) { +